package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.lfasr.concurrent.ConcurrentLockAspect;
import com.xbongbong.paas.business.rule.RuleBusinessLogger;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.PaasProcessDataEntity;
import com.xbongbong.paas.domain.entity.PaasProcessRelatedDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DefaultTypeEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.TaskTypeEnum;
import com.xbongbong.paas.field.DefaultAttrPoJo;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.field.MultiUnitItemPoJo;
import com.xbongbong.paas.field.SubFormPoJo;
import com.xbongbong.paas.field.UnitItemPoJo;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.FormDataValidateProductHelp;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.help.ProGetHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.UserHelp;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.log.pojo.InfoArrPojo;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasProcessDataModel;
import com.xbongbong.paas.model.PaasProcessRelatedDataModel;
import com.xbongbong.paas.model.PaasProcessTemplateModel;
import com.xbongbong.paas.pojo.FieldAttrEntityForImport;
import com.xbongbong.paas.pojo.MultiUnitPricePoJo;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.dto.ImportFormDataDTO;
import com.xbongbong.paas.pojo.dto.ParseSingleRowDataDTO;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.pojo.dto.UserAndDepartmentGetDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.imports.CellTitlePojo;
import com.xbongbong.paas.pojo.imports.CellValuePojo;
import com.xbongbong.paas.pojo.imports.RowGroupPojo;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsListVO;
import com.xbongbong.paas.pojo.vo.ParseSingleRowDataVO;
import com.xbongbong.paas.pojo.vo.UserAndDepartmentGetVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.parent.parse.data.FormDataUpdateGetAnalysisDataHelp;
import com.xbongbong.pro.businessproduct.pojo.dto.BusinessProductListDTO;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.contract.pojo.dto.ContractRestoreOutboundDTO;
import com.xbongbong.pro.detailtab.pojo.OneKeyProduceProductPojo;
import com.xbongbong.pro.detailtab.vo.ProductSummaryVO;
import com.xbongbong.pro.domain.entity.LinkProductRelyEntity;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.AssembleErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.BuinessDefaultErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ImportErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.OutstockErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ProductErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SettleAccountErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.TemplateErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.TransferErrorCodeEnum;
import com.xbongbong.pro.enums.fund.enums.ModelTypeEnum;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainDTO;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainInLinkItemDTO;
import com.xbongbong.pro.instock.pojo.dto.RetMaterielListDTO;
import com.xbongbong.pro.instockproduct.pojo.vo.InstockProductDeleteBatchVO;
import com.xbongbong.pro.inventory.pojo.dto.InventoryResetOutstockIdDTO;
import com.xbongbong.pro.listbatch.pojo.dto.AddLabelDTO;
import com.xbongbong.pro.log.pojo.dto.RuleBusinessLogDTO;
import com.xbongbong.pro.message.constant.OutstockPushConstant;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.pojo.PushRefTypePojo;
import com.xbongbong.pro.message.pojo.dto.MessageRabbitMqDTO;
import com.xbongbong.pro.outstock.pojo.dto.OutStockListDTO;
import com.xbongbong.pro.outstock.pojo.dto.OutstockDeleteBatchDTO;
import com.xbongbong.pro.outstock.pojo.dto.OutstockEditAttrUpdateDTO;
import com.xbongbong.pro.outstock.pojo.dto.OutstockUpdateBatchDTO;
import com.xbongbong.pro.outstock.pojo.dto.OutstockUpdateByBusinessRuleDTO;
import com.xbongbong.pro.outstock.pojo.dto.OutstockUpdateDTO;
import com.xbongbong.pro.outstock.pojo.vo.OutStockListVO;
import com.xbongbong.pro.outstock.pojo.vo.OutstockDeleteBatchVO;
import com.xbongbong.pro.outstockproduct.pojo.dto.FormatOutstockProductDTO;
import com.xbongbong.pro.outstockproduct.pojo.dto.OutstockProductDeleteBatchDTO;
import com.xbongbong.pro.outstockproduct.pojo.vo.OutstockProductDeleteBatchVO;
import com.xbongbong.pro.product.pojo.dto.CostRecalculationDTO;
import com.xbongbong.pro.product.pojo.dto.PagingProductDTO;
import com.xbongbong.pro.product.pojo.vo.DetailProductVO;
import com.xbongbong.pro.product.pojo.vo.PagingProductVO;
import com.xbongbong.pro.rabbitmq.producer.BaseProducer;
import com.xbongbong.pro.rabbitmq.producer.impl.CostRecalculationProducerImpl;
import com.xbongbong.pro.returnedpurchase.pojo.dto.ReturnedPurchaseUpdateBatchDTO;
import com.xbongbong.pro.returnedpurchase.pojo.dto.ReturnedPurchaseUpdateDTO;
import com.xbongbong.pro.thread.ThreadPoolBeanConfig;
import com.xbongbong.pro.transfer.pojo.dto.TransferResetInstockIdDTO;
import com.xbongbong.pro.user.pojo.ReturnUserAndDepartmentPojo;
import com.xbongbong.pro.warehouse.pojo.dto.ProductWarehouseMapDTO;
import com.xbongbong.pro.warehouse.pojo.vo.ProductWarehouseMapVO;
import com.xbongbong.pro.workorder.pojo.dto.WorkOrderRestoreOutboundDTO;
import com.xbongbong.saas.analytical.impl.OutstockValidateAnalyticalServiceImpl;
import com.xbongbong.saas.annotation.BusinessTypeToServiceAnnotation;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.MultiUnitConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.ProductConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.BatchFlowBillUpdateEntity;
import com.xbongbong.saas.domain.entity.BusinessProductEntity;
import com.xbongbong.saas.domain.entity.ContractProductEntity;
import com.xbongbong.saas.domain.entity.OutstockProductEntity;
import com.xbongbong.saas.domain.entity.ProductStockEntity;
import com.xbongbong.saas.domain.entity.ProductStockUpdateEntity;
import com.xbongbong.saas.domain.entity.ProductWarehouseEntity;
import com.xbongbong.saas.domain.entity.PurchaseBalanceEntity;
import com.xbongbong.saas.domain.entity.ReturnedPurchaseProductEntity;
import com.xbongbong.saas.domain.entity.SettleAccountsEntity;
import com.xbongbong.saas.domain.entity.SmartReplenishmentEntity;
import com.xbongbong.saas.domain.entity.StockFlowBillUpdateEntity;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.ContractSubDataExt;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.domain.entity.ext.OutstockEntityExt;
import com.xbongbong.saas.domain.entity.ext.OutstockProductEntityExt;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.domain.entity.ext.RefundEntityExt;
import com.xbongbong.saas.domain.entity.ext.WarehouseEntityExt;
import com.xbongbong.saas.enums.BusinessProductEnum;
import com.xbongbong.saas.enums.BusinessTypeToServiceEnum;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.DistributorAddressEnum;
import com.xbongbong.saas.enums.InstockTypeEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.OutstockTypeEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.RelativeProductEnum;
import com.xbongbong.saas.enums.ReturnedPurchaseStatusEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.StockTypeEnum;
import com.xbongbong.saas.enums.UpdateDataTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.base.RefundBaseEnum;
import com.xbongbong.saas.enums.business.AssembleEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.ContractOutstockEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.InstockEnum;
import com.xbongbong.saas.enums.business.InventoryEnum;
import com.xbongbong.saas.enums.business.OrderEnum;
import com.xbongbong.saas.enums.business.OrderOutStockEnum;
import com.xbongbong.saas.enums.business.OutstockEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.ProductionOrderEnum;
import com.xbongbong.saas.enums.business.ReturnedPurchaseEnum;
import com.xbongbong.saas.enums.business.ReturnedPurchaseOutstockEnum;
import com.xbongbong.saas.enums.business.TransferEnum;
import com.xbongbong.saas.enums.business.WaitOutStockStatusEnum;
import com.xbongbong.saas.enums.business.WarehouseEnum;
import com.xbongbong.saas.enums.business.WorkOrderEnum;
import com.xbongbong.saas.enums.business.WorkOrderOutstockEnum;
import com.xbongbong.saas.enums.dictionary.ReturnedStatusEnum;
import com.xbongbong.saas.enums.product.ContractOutstockProductEnum;
import com.xbongbong.saas.enums.product.InstockProductEnum;
import com.xbongbong.saas.enums.product.OutstockProductEnum;
import com.xbongbong.saas.enums.product.ProductionMaterielOutstockProductEnum;
import com.xbongbong.saas.enums.subform.ProductWarehouseSubFormEnum;
import com.xbongbong.saas.help.BatchSeqExplainHelp;
import com.xbongbong.saas.help.ImportHelper;
import com.xbongbong.saas.help.LogHandleHelp;
import com.xbongbong.saas.help.ReceivablesHelper;
import com.xbongbong.saas.help.RelativeProductHelp;
import com.xbongbong.saas.help.SaasDeleteHelp;
import com.xbongbong.saas.help.SaasOutstockHelp;
import com.xbongbong.saas.help.SaasSaveHelp;
import com.xbongbong.saas.help.SaasUpdateHelp;
import com.xbongbong.saas.help.workflow.ContractHelp;
import com.xbongbong.saas.help.workflow.OutstockHelp;
import com.xbongbong.saas.model.BatchFlowBillModel;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.ContractProductModel;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.CustomerUserModel;
import com.xbongbong.saas.model.InstockProductModel;
import com.xbongbong.saas.model.LinkProductRelyModel;
import com.xbongbong.saas.model.OutstockModel;
import com.xbongbong.saas.model.OutstockProductModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.ProductSerialFlowModel;
import com.xbongbong.saas.model.ProductStockModel;
import com.xbongbong.saas.model.ProductWarehouseModel;
import com.xbongbong.saas.model.PurchaseBalanceModel;
import com.xbongbong.saas.model.RefundModel;
import com.xbongbong.saas.model.ReturnedPurchaseProductModel;
import com.xbongbong.saas.model.SettleAccountsModel;
import com.xbongbong.saas.model.SmartReplenishmentModel;
import com.xbongbong.saas.model.SpecificationModel;
import com.xbongbong.saas.model.StockFlowBillModel;
import com.xbongbong.saas.model.WarehouseModel;
import com.xbongbong.saas.service.BatchFlowBillService;
import com.xbongbong.saas.service.BusinessProductService;
import com.xbongbong.saas.service.ContractService;
import com.xbongbong.saas.service.FormatSpecialBusinessService;
import com.xbongbong.saas.service.FundSetService;
import com.xbongbong.saas.service.InstockProductService;
import com.xbongbong.saas.service.InventoryService;
import com.xbongbong.saas.service.OriStockService;
import com.xbongbong.saas.service.OutstockProductService;
import com.xbongbong.saas.service.OutstockService;
import com.xbongbong.saas.service.PaymentService;
import com.xbongbong.saas.service.ProductSerialService;
import com.xbongbong.saas.service.ProductService;
import com.xbongbong.saas.service.ProductWarehouseService;
import com.xbongbong.saas.service.ProductionOrderService;
import com.xbongbong.saas.service.ReturnedPurchaseService;
import com.xbongbong.saas.service.StockFlowBillService;
import com.xbongbong.saas.service.TransferService;
import com.xbongbong.saas.service.UserTeamService;
import com.xbongbong.saas.service.WaitPurchaseService;
import com.xbongbong.saas.service.WarehouseService;
import com.xbongbong.saas.service.WorkOrderService;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import com.xbongbong.saas.service.toolbox.help.ProductHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.UserModel;
import com.xbongbong.util.OutstockUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.xbongbong.saas.enums.RelativeProductEnum.BARCODE;
import static com.xbongbong.saas.enums.RelativeProductEnum.BATCH;
import static com.xbongbong.saas.enums.RelativeProductEnum.COST;
import static com.xbongbong.saas.enums.RelativeProductEnum.GUARANTEE_PERIOD;
import static com.xbongbong.saas.enums.RelativeProductEnum.MEMO;
import static com.xbongbong.saas.enums.RelativeProductEnum.NAME;
import static com.xbongbong.saas.enums.RelativeProductEnum.NUM;
import static com.xbongbong.saas.enums.RelativeProductEnum.PRODUCE_DATE;
import static com.xbongbong.saas.enums.RelativeProductEnum.PRODUCT_NO;
import static com.xbongbong.saas.enums.RelativeProductEnum.SPECIFICATION;
import static com.xbongbong.saas.enums.RelativeProductEnum.STOCK;
import static com.xbongbong.saas.enums.RelativeProductEnum.UNIT;
import static com.xbongbong.saas.enums.RelativeProductEnum.WAREHOUSE;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author chaoxiong.lei
 * @date 2019/1/20 19:10
 */
@Service("outstockService")
@BusinessTypeToServiceAnnotation(businessService = BusinessTypeToServiceEnum.OUTSTOCK)
public class OutstockServiceImpl implements OutstockService, FormatSpecialBusinessService {

    private static final Logger LOG = LoggerFactory.getLogger(OutstockServiceImpl.class);

    @Resource
    private SaasSaveHelp saasSaveHelp;
    @Resource
    private SaasUpdateHelp saasUpdateHelp;
    @Resource
    private OutstockProductModel outstockProductModel;
    @Resource
    private InstockProductModel instockProductModel;
    @Resource
    private StockFlowBillModel stockFlowBillModel;
    @Resource
    private BatchFlowBillModel batchFlowBillModel;
    @Resource
    private ContractProductModel contractProductModel;
    @Resource
    private ProductModel productModel;
    @Resource
    private OutstockModel outstockModel;
    @Resource
    private ContractService contractService;
    @Resource
    private ProductWarehouseService productWarehouseService;
    @Resource
    private ProductWarehouseModel productWarehouseModel;
    @Resource
    private ContractModel contractModel;
    @Resource
    private SpecificationModel specificationModel;
    @Resource
    private WarehouseService warehouseService;
    @Resource
    private WarehouseModel warehouseModel;
    @Resource
    private OutstockProductService outstockProductService;
    @Resource
    private ReturnedPurchaseService returnedPurchaseService;
    @Resource
    private InventoryService inventoryService;
    @Resource
    private TransferService transferService;
    @Resource
    private ProductionOrderService productionOrderService;
    @Resource
    private ProductService productService;
    @Resource
    private CustomerUserModel customerUserModel;
    @Resource
    private AttrDecimalPrecisionHelper attrDecimalPrecisionHelper;
    @Resource
    private BusinessProductService businessProductService;
    @Resource
    private UserModel userModel;
    @Resource
    private BaseProducer baseProducer;
    @Resource
    private ImportHelper importHelper;
    @Resource
    private ReturnedPurchaseProductModel returnedPurchaseProductModel;
    @Resource
    private ProductStockModel productStockModel;
    @Resource
    private WorkOrderService workOrderService;
    @Resource
    private PaasProcessTemplateModel paasProcessTemplateModel;
    @Resource
    private EsHelper esHelper;
    @Resource
    private ProGetHelp proGetHelp;
    @Resource
    private ThreadPoolBeanConfig threadPoolBeanConfig;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private UserTeamService userTeamService;
    @Resource
    private CostRecalculationProducerImpl costRecalculationProducer;
    @Resource
    @Lazy
    private RuleBusinessLogger ruleBusinessLogger;
    @Resource
    private FormDataValidateProductHelp formDataValidateProductHelp;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private ProductHelp productHelp;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private LinkProductRelyModel linkProductRelyModel;
    @Resource
    private FormDataUpdateGetAnalysisDataHelp formDataUpdateGetAnalysisDataHelp;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private UserHelp userHelp;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    SaasDeleteHelp saasDeleteHelp;
    @Resource
    private ProductSerialService productSerialService;
    @Resource
    private StockFlowBillService stockFlowBillService;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private OriStockService oriStockService;
    @Resource
    private BatchFlowBillService batchFlowBillService;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;
    @Resource
    private PaasProcessRelatedDataModel paasProcessRelatedDataModel;
    @Resource
    private RelativeProductHelp relativeProductHelp;
    @Resource
    private LogHelp logHelp;
    @Resource
    private FundSetService fundSetService;
    @Resource
    private ReceivablesHelper receivablesHelper;
    @Resource
    private LogHandleHelp logHandleHelp;
    @Resource
    private OutstockValidateAnalyticalServiceImpl outstockAnalyticalService;
    @Resource
    private OutstockHelp outstockHelp;
    @Resource
    private PaymentService paymentService;
    @Resource
    private SaasOutstockHelp saasOutstockHelp;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private InstockProductService instockProductService;
    @Resource
    private SettleAccountsModel settleAccountsModel;
    @Resource
    private ConcurrentLockAspect concurrentLockAspect;
    @Resource
    private ProductSerialFlowModel productSerialFlowModel;
    @Resource
    private PurchaseBalanceModel purchaseBalanceModel;
    @Resource
    private SmartReplenishmentModel smartReplenishmentModel;
    @Resource
    private WaitPurchaseService waitPurchaseService;
    @Resource
    private ContractHelp contractHelp;
    @Resource
    private PaasProcessDataModel paasProcessDataModel;
    @Resource
    private RefundModel refundModel;

    @Override
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        outstockAnalyticalService.beforeSave(validateDataDTO);
    }



    @Override
    public void afterSave(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
//        Integer outbound = saasUpdateHelp.getIntegerFromFormData(data, OutstockEnum.OUTBOUND.getAttr());
        JSONObject data = saasFormSaveDTO.getNewData();
        Integer type = data.getInteger(OutstockEnum.TYPE.getAttr());
        String corpid = saasFormSaveDTO.getCorpid();
        ContractEntityExt contractEntityExt = null;
        Long refId = Objects.isNull(data.getLong(OutstockEnum.REF_ID.getAttr())) ? 0L : data.getLong(OutstockEnum.REF_ID.getAttr());
        if (saasFormSaveDTO.getIsNew()) {
            // 改为新建时进行以下逻辑：产品保存、库存更新、上游单据更新
            // 获取对应数据
            PaasFormDataEntity newEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
            JSONObject dataList = newEntity.getData();
            // 获取关联产品的数据
            JSONArray productJsonArray = dataList.getJSONArray(OutstockEnum.PRODUCT.getAttr());
            String productStr = productJsonArray.toJSONString();
            // 更新出库产品库存
            Long outstockId = newEntity.getId();
            //上游单据id
            Long formId = saasFormSaveDTO.getNewPaasFormDataEntity().getFormId();
            saveProduct(productJsonArray, corpid, outstockId, type, refId, formId, false);
            // 序列号入库
            productSerialService.saveSerial(saasFormSaveDTO, productStr);
            // 更新上游单据
            setOutstockDoucmentsNew(saasFormSaveDTO);
            //发送重算参数
            SaasFormSaveDTO saasFormSaveDTOCost = new SaasFormSaveDTO();
            saasFormSaveDTOCost.setCorpid(saasFormSaveDTO.getCorpid());
            saasFormSaveDTOCost.setBusinessType(saasFormSaveDTO.getBusinessType());
            saasFormSaveDTOCost.setNewData(saasFormSaveDTO.getNewData());
            saasFormSaveDTOCost.setNewPaasFormDataEntity(saasFormSaveDTO.getNewPaasFormDataEntity());
            CostRecalculationDTO costRecalculationDTO = new CostRecalculationDTO();
            costRecalculationDTO.setData(data);
            costRecalculationDTO.setMark(BasicConstant.ONE);
            costRecalculationDTO.setType(StockTypeEnum.OUT_STOCK.getCode());
            costRecalculationDTO.setCorpid(corpid);
            costRecalculationDTO.setStockId(outstockId);
            costRecalculationDTO.setIsWorkFlow(BasicConstant.ONE);
            costRecalculationDTO.setSaasFormSaveDTO(saasFormSaveDTOCost);
            //将流水放至重算方法中生成，保证处理的先后顺序
            /*stockFlowBillService.caculateStockModification4Save(saasFormSaveDTO);
            batchFlowBillService.batchFlowModification4Save(saasFormSaveDTO);*/
            costRecalculationProducer.sendMessage(costRecalculationDTO);
            if (saasFormSaveDTO.getIsNew() && Objects.equals(type, OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
                //获取当前处于什么模式
                Long modelType = fundSetService.getModelType(corpid,XbbRefTypeEnum.CRM);
                if(Objects.equals(modelType, ModelTypeEnum.OUTSTOCK.getCode())){
                    receivablesHelper.createReceivablesHandle(saasFormSaveDTO, modelType, null);
                }
                PaasFormDataEntityExt contractFormDataEntity = contractModel.getByKey(refId, corpid);
                contractEntityExt = (ContractEntityExt) contractFormDataEntity;
                // 销售出库消息推送
                Runnable runnable = () -> {
                    try {
                        if (Objects.nonNull(contractFormDataEntity)) {
                            Long customerId = contractFormDataEntity.getData().getLong(ContractEnum.LINK_CUSTOMER.getAttr());
                            //客户负责人
                            List<String> customerUserList = customerUserModel.getCustomerUserIdList(corpid, Collections.singletonList(customerId), null);
                            if (customerUserList == null) {
                                customerUserList = new ArrayList<>();
                            }
                            //合同创建人
                            customerUserList.add(contractFormDataEntity.getCreatorId());
                            //推送给仓库主管
                            List<UserEntity> managers = userModel.getUsersByRoleId(corpid, Collections.singletonList(22));
                            for (UserEntity manager : managers) {
                                customerUserList.add(manager.getUserId());
                            }
                            PushRefTypePojo.Options options = new PushRefTypePojo.Options(contractFormDataEntity.getAppId(), contractFormDataEntity.getMenuId(), contractFormDataEntity.getFormId(), refId, Collections.singletonList(refId), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.CONTRACT.getCode(), XbbRefTypeEnum.CONTRACT.getCode());
                            MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(saasFormSaveDTO.getCorpid(), customerUserList, Collections.singletonList(refId), 0, null, I18nMessageUtil.getMessage(OutstockPushConstant.OUTSTOCK_TITLE), String.format(I18nMessageUtil.getMessage(OutstockPushConstant.CONTRACT_OUTSTOCK_CONTENT), contractFormDataEntity.getSerialNo()), null, options);
                            baseProducer.sendMessage(PushTypeEnum.OUTSTOCK_SUCCESS_PUSH, messageRabbitMqDTO);
                        }
                    } catch (Exception e) {
                        LOG.error("销售出库消息推送", e);
                    }
                };
                threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
            }
        } else if (Objects.equals(type,OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())){
            Map<String, FieldAttrEntity> explainMap = saasFormSaveDTO.getExplainMap();
            FieldAttrEntity nameFieldAttrEntity = explainMap.get(ContractOutstockEnum.EXPRESS_NAME.getAttr());
            FieldAttrEntity noFieldAttrEntity = explainMap.get(ContractOutstockEnum.EXPRESS_NO.getAttr());
            Object expressName = data.get(OutstockEnum.EXPRESS_NAME.getAttr());
            Object expressNo = data.get(OutstockEnum.EXPRESS_NO.getAttr());
            boolean updateExpressName = Objects.nonNull(nameFieldAttrEntity) && !Objects.equals(saasFormSaveDTO.getOldData().getString(OutstockEnum.EXPRESS_NAME.getAttr()), expressName);
            boolean updateExpressNo = Objects.nonNull(noFieldAttrEntity) && !Objects.equals(saasFormSaveDTO.getOldData().getString(OutstockEnum.EXPRESS_NO.getAttr()), expressNo);
            contractEntityExt = contractModel.getByKey(refId, corpid);
            if (updateExpressName || updateExpressNo) {
                if (updateExpressName && Objects.nonNull(expressName)) {
                    contractEntityExt.getData().put(ContractEnum.EXPRESS_NAME.getAttr(), data.get(OutstockEnum.EXPRESS_NAME.getAttr()));
                }
                if (updateExpressNo && Objects.nonNull(expressNo)) {
                    contractEntityExt.getData().put(ContractEnum.EXPRESS_NO.getAttr(), data.get(OutstockEnum.EXPRESS_NO.getAttr()));
                }
            }
        }
        if(Objects.nonNull(contractEntityExt) && MapUtils.isNotEmpty(contractEntityExt.getData()) && contractEntityExt.getData().containsKey(ContractEnum.OUTSTOCK_ID.getAttr())){
            JSONObject contractEntityExtData = contractEntityExt.getData();
            String outstockIdAttr = ContractEnum.OUTSTOCK_ID.getAttr();
            // 获取合同订单的全部出库单ID
            List<Long> outStockIdList = new ArrayList<>();
            JSONArray jsonArray = contractEntityExtData.getJSONArray(outstockIdAttr);
            for (int i = 0; i < jsonArray.size(); i++) {
                outStockIdList.add(jsonArray.getLong(i));
            }
            // 优惠金额
            String discountAmountAttr = ContractOutstockEnum.DISCOUNT_AMOUNT.getAttr();
            // 其他费用
            String otherExpenseAttr = ContractOutstockEnum.OTHER_EXPENSE.getAttr();
            List<String> attrs = Arrays.asList(discountAmountAttr, otherExpenseAttr);
            Map<String, BigDecimal> attrSumMap = outstockModel.sumJsonByIdAndAttr(corpid, outStockIdList, attrs);
            contractEntityExtData.put(ContractEnum.OUTSTOCK_DISCOUNT_AMOUNT.getAttr(), attrSumMap.getOrDefault(discountAmountAttr, BigDecimal.ZERO));
            contractEntityExtData.put(ContractEnum.OUTSTOCK_OTHER_EXPENSE.getAttr(), attrSumMap.getOrDefault(otherExpenseAttr, BigDecimal.ZERO));
            // 更新合同数据
            contractModel.update(contractEntityExt);
        }
    }

    public void setOutstockDoucmentsNew(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        outstockHelp.setOutstockDocumentsNew(saasFormSaveDTO.getCorpid(), saasFormSaveDTO.getNewData(), saasFormSaveDTO.getDistributorMark(), saasFormSaveDTO.getNewPaasFormDataEntity());
    }

    @Override
    public void saveProduct(JSONArray productArray, String corpid, Long outstockId, Integer type, Long refId, Long formId, boolean isWorkflow) throws XbbException {
        List<Long> childProductIdList = new ArrayList<>();
        //新增
        List<OutstockProductEntity> addOutstockProductEntityList = new ArrayList<>();
        Map<Long, PaasFormDataEntityExt> productMap = formDataValidateProductHelp.product2saveMap(corpid,productArray);
        Integer sort = 0;
        List<Long> warehouseIdList = new ArrayList<>();
        Map<Long, Map<Long, String>> warehouseMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject jsonObject = productArray.getJSONObject(i);
            // 移除序列号相关数据，不存入关联产品数据中
            jsonObject.remove(ProductConstant.SEQ);
            jsonObject.remove(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr());
            jsonObject.remove(ProductEnum.ENABLE_BATCH_SHELF_LIFE.getSaasAttr());

            Long pageProductId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            childProductIdList.add(pageProductId);
            sort++;
            JSONObject productData = productMap.get(pageProductId).getData();
            OutstockProductEntity entity = new OutstockProductEntity();
            entity.setCorpid(corpid);
            entity.setProductId(pageProductId);
            entity.setParentId(productData.getLong(ProductEnum.PARENT_ID.getAttr()));
            jsonObject.put(ProductEnum.PARENT_ID.getSaasAttr(), productData.getLong(ProductEnum.PARENT_ID.getAttr()));
            entity.setProductNo(productData.getString(ProductEnum.PRODUCT_NO.getAttr()));
            entity.setProductNum(jsonObject.getDouble(OutstockProductEnum.NUM.getAttr()));
            entity.setOutWarehouseId(outstockId);
            entity.setInstockNum(0D);
            entity.setType(type);
            entity.setRefId(refId);
            entity.setFormId(formId);
            if (Objects.nonNull(jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID))) {
                entity.setRefProductId(jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID));
            }
            saasSaveHelp.formatLinkBusiness4Save(jsonObject,OutstockProductEnum.WAREHOUSE.getAttr(), "warehouseName", FieldTypeEnum.LINK_BUSINESS_SINGLE.getType());
            entity.setWarehouseId(jsonObject.getLong(OutstockProductEnum.WAREHOUSE.getAttr()));
            entity.setWarehouseName(jsonObject.getString("warehouseName"));
            entity.setProductName(productData.getString(ProductEnum.NAME.getAttr()));
            entity.setProductSpecification(productData.getString(ProductEnum.SPECIFICATION_LINK_TEXT.getAttr()));
            entity.setSort(sort);
            entity.setMemo(jsonObject.getString(OutstockProductEnum.MEMO.getAttr()));
            entity.setBatch(Objects.isNull(jsonObject.getString(OutstockProductEnum.BATCH.getAttr())) ? "" : jsonObject.getString(OutstockProductEnum.BATCH.getAttr()));
            Long guaranteePeriod = Objects.isNull(jsonObject.getLong(OutstockProductEnum.GUARANTEE_PERIOD.getAttr())) ? 0L : jsonObject.getLong(OutstockProductEnum.GUARANTEE_PERIOD.getAttr()) * TimeConstant.SECONDS_PER_DAY;
            entity.setGuaranteePeriod(guaranteePeriod);
            Long produceDate = Objects.isNull(jsonObject.getLong(OutstockProductEnum.PRODUCE_DATE.getAttr())) ? 0L : jsonObject.getLong(OutstockProductEnum.PRODUCE_DATE.getAttr());
            entity.setProduceDate(produceDate);
            entity.setCost(Objects.isNull(jsonObject.getDouble(ProductEnum.COST.getAttr())) ? 0D : jsonObject.getDouble(ProductEnum.COST.getAttr()));
            if (Objects.equals(type,OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())){
                entity.setDiscount(jsonObject.getDouble(ContractOutstockProductEnum.DISCOUNT.getAttr()));
                entity.setProductPrice(jsonObject.getDouble(ContractOutstockProductEnum.SELLING_PRICE.getAttr()));
            }
            jsonObject.put(OutstockProductEnum.TOTAL_COST.getAttr(), Arith.mul(entity.getCost(), entity.getProductNum()));
            entity.setData(jsonObject);
            if (Objects.nonNull(entity.getWarehouseId())) {
                warehouseIdList.add(entity.getWarehouseId());
            }
            Integer enableMultiUnit = productData.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr());
            if (Objects.equals(enableMultiUnit, 1)) {
                formDataValidateProductHelp.setBusinessUnit(jsonObject, entity);
                entity.setProductUnit(jsonObject.getString(SelectProductEnum.UNIT.getAttr()));
            } else {
                entity.setProductUnit(productData.getString(ProductEnum.UNIT.getAttr()));
                jsonObject.put(OutstockProductEnum.UNIT.getAttr(),productData.getString(ProductEnum.UNIT.getAttr()));
            }
            addOutstockProductEntityList.add(entity);
            warehouseMap.put(pageProductId, new HashMap<Long, String>() {{
                put(entity.getWarehouseId(), entity.getWarehouseName());
            }});
        }
        if (!addOutstockProductEntityList.isEmpty()){
            outstockProductModel.insertBatch(addOutstockProductEntityList);
        }
        // 销售出库单正常新建及老审批流新建销售出库单时 更新对应采购结存数据
        if (Objects.equals(type, OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
            List<OutstockProductEntity> outstockProductList = new ArrayList<>();
            for (OutstockProductEntity outstockProductEntity : addOutstockProductEntityList) {
                OutstockProductEntity newOutstockProductEntity = new OutstockProductEntity();
                BeanUtil.copyProperties(outstockProductEntity, newOutstockProductEntity);
                outstockProductList.add(newOutstockProductEntity);
            }
            waitPurchaseService.formatContractOutstock(corpid, outstockProductList);
        }
        // 流水台账需要
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject jsonObject = productArray.getJSONObject(i);
            jsonObject.put(BusinessConstant.PRODUCT_SUB_ID, addOutstockProductEntityList.get(i).getId());
        }
        if (!isWorkflow) {
            //更新出库单产品的分仓库存、批次库存
            Map<Long, ProductStockUpdateEntity> productAddMap = outstockProductService.addUpdateStock(addOutstockProductEntityList,corpid);
            productService.updateProductStock(productAddMap,corpid);
        }
    }

    @Override
    public OutStockListVO findOutstockList(OutStockListDTO outStockListDTO) throws XbbException {
        OutStockListVO outStockListVO = new OutStockListVO();
        try {
            List<PaasFormDataEntityExt> outstockList = outstockModel.findOutstockList(outStockListDTO.getRefIdIn(), outStockListDTO.getType(), outStockListDTO.getFlowStatusIn(), outStockListDTO.getCorpid(), outStockListDTO.getFieldList());
            if (Objects.isNull(outstockList)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
            }
            outStockListVO.setOutstockList(outstockList);
        } catch (Exception e) {
            LOG.error("outstockServiceImpl.findOutstockList获取出库单出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return outStockListVO;
    }

    @Override
    public PaasFormDataEsListVO getOutstockListFromEs(String corpid, Long refId, Integer type, Integer distributorMark) throws XbbException {
        return saasOutstockHelp.getOutstockListFromEs(corpid, refId, type, distributorMark);
    }

    @Override
    public void formatProduct4Show2(Long dataId, String corpid, JSONObject data, Boolean forProcess, Integer operate,  UpdateDataTypeEnum updateDataTypeEnum) throws XbbException {
        outstockModel.formatProduct4Show2(dataId, corpid, data, forProcess, operate, updateDataTypeEnum);
    }

    @Override
    public PagingProductVO getPagingProduct(PagingProductDTO pagingProductDTO) throws XbbException {
        PagingProductVO pagingProductVO = new PagingProductVO();
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, pagingProductDTO.getCorpid());
        modelMap.put(ParameterConstant.OUT_WAREHOUSE_ID, pagingProductDTO.getDataId());
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put(ParameterConstant.PAGE,  pagingProductDTO.getPage());
        modelMap.put(ParameterConstant.ORDER_BY_STR, BasicConstant.SORT);
        PageHelper pageHelper = PageHelperUtil.getPageHelper(modelMap, outstockProductModel, pagingProductDTO.getPageSize());
        List<OutstockProductEntity> outstockProductEntityList = (List<OutstockProductEntity>) PageHelperUtil.getEntityList(modelMap, pageHelper, outstockProductModel);
        if (pagingProductDTO.getUpdateDataTypeEnum().isDetail()) {
            DetailProductVO detailProductVO = formatProduct4DetailShow(outstockProductEntityList, pagingProductDTO);
            pagingProductVO.setProductDataArr(detailProductVO.getProductDataArr());
        }
        pagingProductVO.setPageHelper(pageHelper);
        return pagingProductVO;
    }

    public DetailProductVO formatProduct4DetailShow(List<OutstockProductEntity> outstockProductEntityList, PagingProductDTO pagingProductDTO) throws XbbException{
        DetailProductVO detailProductVO = new DetailProductVO();
        Set<Long> productIds = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> warehouseIdList = new ArrayList<>();
        List<String> batchKeyList = new ArrayList<>();
        Set<String> warehouseKeySet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (OutstockProductEntity outstockProductEntity : outstockProductEntityList) {
            productIds.add(outstockProductEntity.getProductId());
            warehouseIdList.add(outstockProductEntity.getWarehouseId());
            String key = formDataValidateProductHelp.getBatchKey(outstockProductEntity.getProductId(), outstockProductEntity.getWarehouseId(), outstockProductEntity.getBatch(), outstockProductEntity.getProduceDate(), outstockProductEntity.getGuaranteePeriod());
            batchKeyList.add(key);
            warehouseKeySet.add(outstockProductEntity.getProductId() + "_" + outstockProductEntity.getWarehouseId());
        }
        List<PaasFormDataEntityExt> warehouseList = paasEsModel.getByIdList(warehouseIdList, pagingProductDTO.getCorpid(), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.WAREHOUSE.getCode(), new ArrayList<>(), IndexTypeEnum.IDX_SAAS_WAREHOUSE);
        Map<Long, String> warehouseNameMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (PaasFormDataEntityExt paasFormDataEntityExt : warehouseList) {
            JSONObject data = paasFormDataEntityExt.getData();
            warehouseNameMap.put(paasFormDataEntityExt.getId(), FastJsonHelper.getStringOrDefaultFromFormData(data, WarehouseEnum.WAREHOUSE_NAME.getAttr(), ""));
        }
        String corpid = pagingProductDTO.getCorpid();
        JSONArray productArray = new JSONArray();
        Map<Long, PaasFormDataEntityExt> productMap = productService.getProductMapByIdIn(productIds, corpid, DelEnum.NORMAL);
        PaasFormExplainEntity productExplains = paasFormExplainModel.getByBusinessType(XbbRefTypeEnum.PRODUCT.getCode(), corpid);
        // 分仓库存
        Map<String, Double> productWarehouseMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (!productIds.isEmpty() && !warehouseIdList.isEmpty()) {
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("del", DelEnum.NORMAL.getDel());
            params.put(ParameterConstant.CORPID, corpid);
//            params.put("productIdIn", productIds);
//            params.put("warehouseIdIn", warehouseIdList);
            params.put("warehouseKeyIn",warehouseKeySet);
            List<ProductWarehouseEntity> productWarehouseEntities = productWarehouseModel.findEntitysWithWarehouseChecked(params,null);
            productWarehouseEntities.forEach(item -> {
                String key = item.getProductId() + "_" + item.getWarehouseId();
                productWarehouseMap.put(key, item.getNum());
            });
        }
        //批次库存
        if (!batchKeyList.isEmpty()) {
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("del", DelEnum.NORMAL.getDel());
            params.put(ParameterConstant.CORPID, corpid);
            params.put("batchKeyIn", batchKeyList);
            List<ProductStockEntity> productStockEntities = productStockModel.findEntitys(params);
            productStockEntities.forEach(item -> {
                productWarehouseMap.put(item.getBatchKey(), item.getNum());
            });
        }
        if (Objects.isNull(productExplains)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> productExplainMap = ExplainUtil.getExplainMap(productExplains.getExplains(), null);
        for (OutstockProductEntity outstockProductEntity : outstockProductEntityList) {
            Double stock;
            if (StringUtil.isNotEmpty(outstockProductEntity.getBatch())) {
                stock = productWarehouseMap.getOrDefault(formDataValidateProductHelp.getBatchKey(outstockProductEntity.getProductId(), outstockProductEntity.getWarehouseId(), outstockProductEntity.getBatch(), outstockProductEntity.getProduceDate(), outstockProductEntity.getGuaranteePeriod()), 0D);
            } else {
                stock = productWarehouseMap.getOrDefault(outstockProductEntity.getProductId() + "_" + outstockProductEntity.getWarehouseId(), 0D);
            }
            PaasFormDataEntityExt paasFormDataEntityExt = productMap.get(outstockProductEntity.getProductId());
            JSONObject json = new JSONObject();
            if (Objects.nonNull(outstockProductEntity.getData())) {
                json = outstockProductEntity.getData();
            }
            if (Objects.nonNull(outstockProductEntity.getBusinessUnit())) {
                outstockProductEntity.setProductNum(Arith.div(outstockProductEntity.getProductNum(), outstockProductEntity.getRate()));
                outstockProductEntity.setProductUnit(outstockProductEntity.getBusinessUnit().toString());
                JSONObject priceData = outstockProductEntity.getPriceData();
                if (Objects.nonNull(priceData) && !priceData.isEmpty()) {
                    outstockProductEntity.setCost(priceData.getDouble(SelectProductEnum.COST.getAttr()));
                }
            }
            for (OutstockProductEnum outstockProductEnum : OutstockProductEnum.values()) {
                if (!UpdateDataTypeEnum.DETAIL.formatShow(outstockProductEnum.getShowType())) {
                    continue;
                }
                String attr = outstockProductEnum.getAttr();
                switch (outstockProductEnum) {
                    case PRODUCT:
                        json.put(attr, outstockProductEntity.getProductId());
                        break;
                    case WAREHOUSE:
                        JSONArray warehouseArr = productHelp.packegeLinkBusinessJsonArray(outstockProductEntity.getWarehouseId(),
                                warehouseNameMap.getOrDefault(outstockProductEntity.getWarehouseId(), ""), XbbRefTypeEnum.WAREHOUSE.getCode(), SaasMarkEnum.SAAS.getCode());
                        json.put(attr, warehouseArr);
                        break;
                    case NUM:
                        json.put(attr, outstockProductEntity.getProductNum());
                        break;
                    case COST:
                        json.put(attr, outstockProductEntity.getCost());
                        break;
                    case TOTAL_COST:
                        if (Objects.nonNull(outstockProductEntity.getCost()) && Objects.nonNull(outstockProductEntity.getProductNum())) {
                            json.put(attr, Arith.mul(outstockProductEntity.getProductNum(), outstockProductEntity.getCost()));
                        }
                        break;
                    case STOCK:
                        json.put(attr, stock);
                        break;
                    case MEMO:
                        json.put(attr, outstockProductEntity.getMemo());
                        break;
                    case BATCH:
                        json.put(attr, outstockProductEntity.getBatch());
                        break;
                    case PRODUCE_DATE:
                        if (Objects.nonNull(outstockProductEntity.getProduceDate())){
                            json.put(attr, outstockProductEntity.getProduceDate());
                        }
                        break;
                    case GUARANTEE_PERIOD:
                        if (Objects.nonNull(outstockProductEntity.getGuaranteePeriod()) && !Objects.equals(outstockProductEntity.getProduceDate(), 0L)) {
                            json.put(attr, Arith.div(outstockProductEntity.getGuaranteePeriod(), 86400D));
                        } else {
                            json.remove(attr);
                        }
                        break;
                    case EXPIRE_DATE:
                        if (Objects.nonNull(outstockProductEntity.getGuaranteePeriod()) && Objects.nonNull(outstockProductEntity.getProduceDate())) {
                            json.put(attr, Arith.add(outstockProductEntity.getProduceDate(), outstockProductEntity.getGuaranteePeriod()));
                        }
                        break;
                    case UNIT:
                        json.put(attr, outstockProductEntity.getProductUnit());
                        break;
                    default:
                        break;
                }
            }
            json.put(BusinessConstant.PRODUCT_SUB_ID, outstockProductEntity.getId());
            productArray.add(json);
        }
        detailProductVO.setProductDataArr(productArray);
        return detailProductVO;
    }

    @Override
    public PagingProductVO getPagingProductionMaterielOutstockProduct(PagingProductDTO pagingProductDTO) throws XbbException{
        PagingProductVO pagingProductVO = new PagingProductVO();
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, pagingProductDTO.getCorpid());
        modelMap.put(ParameterConstant.OUT_WAREHOUSE_ID, pagingProductDTO.getDataId());
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put(ParameterConstant.PAGE,  pagingProductDTO.getPage());
        modelMap.put(ParameterConstant.ORDER_BY_STR, BasicConstant.SORT);
        PageHelper pageHelper = PageHelperUtil.getPageHelper(modelMap, outstockProductModel, pagingProductDTO.getPageSize());
        List<OutstockProductEntity> outstockProductEntityList = (List<OutstockProductEntity>) PageHelperUtil.getEntityList(modelMap, pageHelper, outstockProductModel);
        if (pagingProductDTO.getUpdateDataTypeEnum().isDetail()) {
            DetailProductVO detailProductVO = formatProductionMaterielOutstockProduct4DetailShow(outstockProductEntityList, pagingProductDTO);
            pagingProductVO.setProductDataArr(detailProductVO.getProductDataArr());
        }
        pagingProductVO.setPageHelper(pageHelper);
        return pagingProductVO;
    }

    @Override
    public PagingProductVO getPagingContractOutstockProduct(PagingProductDTO pagingProductDTO) throws XbbException {
        PagingProductVO pagingProductVO = new PagingProductVO();
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, pagingProductDTO.getCorpid());
        modelMap.put(ParameterConstant.OUT_WAREHOUSE_ID, pagingProductDTO.getDataId());
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put(ParameterConstant.PAGE,  pagingProductDTO.getPage());
        modelMap.put(ParameterConstant.ORDER_BY_STR, BasicConstant.SORT);
        PageHelper pageHelper = PageHelperUtil.getPageHelper(modelMap, outstockProductModel, pagingProductDTO.getPageSize());
        List<OutstockProductEntity> outstockProductEntityList = (List<OutstockProductEntity>) PageHelperUtil.getEntityList(modelMap, pageHelper, outstockProductModel);
        if (pagingProductDTO.getUpdateDataTypeEnum().isDetail()) {
            DetailProductVO detailProductVO = formatContractOutstockProduct4DetailShow(outstockProductEntityList, pagingProductDTO);
            pagingProductVO.setProductDataArr(detailProductVO.getProductDataArr());
        }
        pagingProductVO.setPageHelper(pageHelper);
        return pagingProductVO;
    }

    /**
    * @Description: 生产领料单
    * @Param: [outstockProductEntityList, pagingProductDTO]
    * @return: com.xbongbong.pro.product.pojo.vo.DetailProductVO
    * @Author: cyy
    * @Date: 2019/12/17
    */
    private DetailProductVO formatProductionMaterielOutstockProduct4DetailShow(List<OutstockProductEntity> outstockProductEntityList, PagingProductDTO pagingProductDTO) throws XbbException{
        DetailProductVO detailProductVO = new DetailProductVO();
        Set<Long> productIds = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> warehouseIdList = new ArrayList<>();
        List<String> batchKeyList = new ArrayList<>();
        Set<String> warehouseKeySet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (OutstockProductEntity outstockProductEntity : outstockProductEntityList) {
            productIds.add(outstockProductEntity.getProductId());
            warehouseIdList.add(outstockProductEntity.getWarehouseId());
            if (StringUtil.isNotEmpty(outstockProductEntity.getBatch())) {
                String key = formDataValidateProductHelp.getBatchKey(outstockProductEntity.getProductId(), outstockProductEntity.getWarehouseId(), outstockProductEntity.getBatch(), outstockProductEntity.getProduceDate(), outstockProductEntity.getGuaranteePeriod());
                batchKeyList.add(key);
            }
            warehouseKeySet.add(outstockProductEntity.getProductId() + "_" + outstockProductEntity.getWarehouseId());
        }
        List<PaasFormDataEntityExt> warehouseList = paasEsModel.getByIdList(warehouseIdList, pagingProductDTO.getCorpid(), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.WAREHOUSE.getCode(), new ArrayList<>(), IndexTypeEnum.IDX_SAAS_WAREHOUSE);
        Map<Long, String> warehouseNameMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (PaasFormDataEntityExt paasFormDataEntityExt : warehouseList) {
            JSONObject data = paasFormDataEntityExt.getData();
            warehouseNameMap.put(paasFormDataEntityExt.getId(), FastJsonHelper.getStringOrDefaultFromFormData(data, WarehouseEnum.WAREHOUSE_NAME.getAttr(), ""));
        }
        String corpid = pagingProductDTO.getCorpid();
        JSONArray productArray = new JSONArray();
        Map<Long, PaasFormDataEntityExt> productMap = productService.getProductMapByIdIn(productIds, corpid, DelEnum.NORMAL);
        // 分仓库存
        Map<String, Double> productWarehouseMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (!productIds.isEmpty() && !warehouseIdList.isEmpty()) {
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("del", DelEnum.NORMAL.getDel());
            params.put(ParameterConstant.CORPID, corpid);
//            params.put("productIdIn", productIds);
//            params.put("warehouseIdIn", warehouseIdList);
            params.put("warehouseKeyIn",warehouseKeySet);
            List<ProductWarehouseEntity> productWarehouseEntities = productWarehouseModel.findEntitysWithWarehouseChecked(params,null);
            productWarehouseEntities.forEach(item -> {
                String key = item.getProductId() + "_" + item.getWarehouseId();
                productWarehouseMap.put(key, item.getNum());
            });
        }
        //批次库存
        if (!batchKeyList.isEmpty()) {
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("del", DelEnum.NORMAL.getDel());
            params.put(ParameterConstant.CORPID, corpid);
            params.put("batchKeyIn", batchKeyList);
            List<ProductStockEntity> productStockEntities = productStockModel.findEntitys(params);
            productStockEntities.forEach(item -> {
                productWarehouseMap.put(item.getBatchKey(), item.getNum());
            });
        }
        for (OutstockProductEntity outstockProductEntity : outstockProductEntityList) {
            Double stock;
            if (StringUtil.isNotEmpty(outstockProductEntity.getBatch())) {
                stock = productWarehouseMap.getOrDefault(formDataValidateProductHelp.getBatchKey(outstockProductEntity.getProductId(), outstockProductEntity.getWarehouseId(), outstockProductEntity.getBatch(), outstockProductEntity.getProduceDate(), outstockProductEntity.getGuaranteePeriod()), 0D);
            } else {
                stock = productWarehouseMap.getOrDefault(outstockProductEntity.getProductId() + "_" + outstockProductEntity.getWarehouseId(), 0D);
            }
            JSONObject json = new JSONObject();
            if (Objects.nonNull(outstockProductEntity.getData())) {
                json = outstockProductEntity.getData();
            }
            if (Objects.nonNull(outstockProductEntity.getBusinessUnit())) {
                outstockProductEntity.setProductNum(Arith.div(outstockProductEntity.getProductNum(), outstockProductEntity.getRate()));
                outstockProductEntity.setProductUnit(outstockProductEntity.getBusinessUnit().toString());
                JSONObject priceData = outstockProductEntity.getPriceData();
                if (Objects.nonNull(priceData) && !priceData.isEmpty()) {
                    outstockProductEntity.setCost(priceData.getDouble(SelectProductEnum.COST.getAttr()));
                }
            }
            for (ProductionMaterielOutstockProductEnum productionMaterielOutstockProductEnum : ProductionMaterielOutstockProductEnum.values()) {
                if (!UpdateDataTypeEnum.DETAIL.formatShow(productionMaterielOutstockProductEnum.getShowType())) {
                    continue;
                }
                String attr = productionMaterielOutstockProductEnum.getAttr();
                switch (productionMaterielOutstockProductEnum) {
                    case PRODUCT:
                        json.put(attr, outstockProductEntity.getProductId());
                        break;
                    case WAREHOUSE:
                        JSONArray warehouseArr = productHelp.packegeLinkBusinessJsonArray(outstockProductEntity.getWarehouseId(),
                                warehouseNameMap.getOrDefault(outstockProductEntity.getWarehouseId(), ""), XbbRefTypeEnum.WAREHOUSE.getCode(), SaasMarkEnum.SAAS.getCode());
                        json.put(attr, warehouseArr);
                        break;
                    case NUM:
                        json.put(attr, outstockProductEntity.getProductNum());
                        break;
                    case COST:
                        json.put(attr, outstockProductEntity.getCost());
                        break;
                    case TOTAL_COST:
                        if (Objects.nonNull(outstockProductEntity.getCost()) && Objects.nonNull(outstockProductEntity.getProductNum())) {
                            json.put(attr, Arith.mul(outstockProductEntity.getProductNum(), outstockProductEntity.getCost()));
                        }
                        break;
                    case STOCK:
                        json.put(attr, stock);
                        break;
                    case MEMO:
                        json.put(attr, outstockProductEntity.getMemo());
                        break;
                    case BATCH:
                        json.put(attr, outstockProductEntity.getBatch());
                        break;
                    case PRODUCE_DATE:
                        json.put(attr, outstockProductEntity.getProduceDate());
                        break;
                    case GUARANTEE_PERIOD:
                        if (Objects.nonNull(outstockProductEntity.getGuaranteePeriod()) && !Objects.equals(outstockProductEntity.getProduceDate(), 0L)) {
                            json.put(attr, Arith.div(outstockProductEntity.getGuaranteePeriod(), TimeConstant.SECONDS_PER_DAY));
                        } else {
                            json.remove(attr);
                        }
                        break;
                    case EXPIRE_DATE:
                        if (Objects.nonNull(outstockProductEntity.getGuaranteePeriod()) && Objects.nonNull(outstockProductEntity.getProduceDate())) {
                            json.put(attr, Arith.add(outstockProductEntity.getProduceDate(), outstockProductEntity.getGuaranteePeriod()));
                        }
                        break;
                    case UNIT:
                        json.put(attr, outstockProductEntity.getProductUnit());
                        break;
                    case RETURN_NUM:
                        json.put(attr, outstockProductEntity.getInstockNum());
                        break;
                    default:
                        break;
                }
            }
            json.put(BusinessConstant.PRODUCT_SUB_ID, outstockProductEntity.getId());
            productArray.add(json);
        }
        detailProductVO.setProductDataArr(productArray);
        return detailProductVO;
    }
    private DetailProductVO formatContractOutstockProduct4DetailShow(List<OutstockProductEntity> outstockProductEntityList, PagingProductDTO pagingProductDTO) throws XbbException{
        DetailProductVO detailProductVO = new DetailProductVO();
        Set<Long> productIds = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> warehouseIdList = new ArrayList<>();
        List<String> batchKeyList = new ArrayList<>();
        Set<String> warehouseKeySet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (OutstockProductEntity outstockProductEntity : outstockProductEntityList) {
            productIds.add(outstockProductEntity.getProductId());
            warehouseIdList.add(outstockProductEntity.getWarehouseId());
            if (StringUtil.isNotEmpty(outstockProductEntity.getBatch())) {
                String key = formDataValidateProductHelp.getBatchKey(outstockProductEntity.getProductId(), outstockProductEntity.getWarehouseId(), outstockProductEntity.getBatch(), outstockProductEntity.getProduceDate(), outstockProductEntity.getGuaranteePeriod());
                batchKeyList.add(key);
            }
            warehouseKeySet.add(outstockProductEntity.getProductId() + "_" + outstockProductEntity.getWarehouseId());
        }
        List<PaasFormDataEntityExt> warehouseList = paasEsModel.getByIdList(warehouseIdList, pagingProductDTO.getCorpid(), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.WAREHOUSE.getCode(), new ArrayList<>(), IndexTypeEnum.IDX_SAAS_WAREHOUSE);
        Map<Long, String> warehouseNameMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (PaasFormDataEntityExt paasFormDataEntityExt : warehouseList) {
            JSONObject data = paasFormDataEntityExt.getData();
            warehouseNameMap.put(paasFormDataEntityExt.getId(), FastJsonHelper.getStringOrDefaultFromFormData(data, WarehouseEnum.WAREHOUSE_NAME.getAttr(), ""));
        }
        String corpid = pagingProductDTO.getCorpid();
        JSONArray productArray = new JSONArray();
//        Map<Long, PaasFormDataEntityExt> productMap = productService.getProductMapByIdIn(productIds, corpid, DelEnum.NORMAL);
        // 分仓库存
        Map<String, Double> productWarehouseMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (!warehouseKeySet.isEmpty()) {
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("del", DelEnum.NORMAL.getDel());
            params.put(ParameterConstant.CORPID, corpid);
//            params.put("productIdIn", productIds);
//            params.put("warehouseIdIn", warehouseIdList);
            params.put("warehouseKeyIn",warehouseKeySet);
            List<ProductWarehouseEntity> productWarehouseEntities = productWarehouseModel.findEntitysWithWarehouseChecked(params,null);
            productWarehouseEntities.forEach(item -> {
                String key = item.getProductId() + "_" + item.getWarehouseId();
                productWarehouseMap.put(key, item.getNum());
            });
        }
        //批次库存
        if (!batchKeyList.isEmpty()) {
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("del", DelEnum.NORMAL.getDel());
            params.put(ParameterConstant.CORPID, corpid);
            params.put("batchKeyIn", batchKeyList);
            List<ProductStockEntity> productStockEntities = productStockModel.findEntitys(params);
            productStockEntities.forEach(item -> {
                productWarehouseMap.put(item.getBatchKey(), item.getNum());
            });
        }

        PaasFormExplainEntity productExplains = paasFormExplainModel.getByBusinessType(XbbRefTypeEnum.PRODUCT.getCode(), corpid);
        if (Objects.isNull(productExplains)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> productExplainMap = ExplainUtil.getExplainMap(productExplains.getExplains(), null);
        for (OutstockProductEntity outstockProductEntity : outstockProductEntityList) {
            Double stock;
            if (StringUtil.isNotEmpty(outstockProductEntity.getBatch())) {
                stock = productWarehouseMap.getOrDefault(formDataValidateProductHelp.getBatchKey(outstockProductEntity.getProductId(), outstockProductEntity.getWarehouseId(), outstockProductEntity.getBatch(), outstockProductEntity.getProduceDate(), outstockProductEntity.getGuaranteePeriod()), 0D);
            } else {
                stock = productWarehouseMap.getOrDefault(outstockProductEntity.getProductId() + "_" + outstockProductEntity.getWarehouseId(), 0D);
            }
//            PaasFormDataEntityExt paasFormDataEntityExt = productMap.get(outstockProductEntity.getProductId());
            JSONObject json = new JSONObject();
            if (Objects.nonNull(outstockProductEntity.getData())) {
                json = outstockProductEntity.getData();
            }
            if (Objects.nonNull(outstockProductEntity.getBusinessUnit())) {
                outstockProductEntity.setProductNum(Arith.div(outstockProductEntity.getProductNum(), outstockProductEntity.getRate()));
                outstockProductEntity.setProductUnit(outstockProductEntity.getBusinessUnit().toString());
                JSONObject priceData = outstockProductEntity.getPriceData();
                if (Objects.nonNull(priceData) && !priceData.isEmpty()) {
                    outstockProductEntity.setCost(priceData.getDouble(SelectProductEnum.COST.getAttr()));
                    outstockProductEntity.setProductPrice(priceData.getDouble(SelectProductEnum.SELLING_PRICE.getAttr()));
                    json.put(SelectProductEnum.PRICE.getAttr(), priceData.getDouble(SelectProductEnum.PRICE.getAttr()));
                }
            }
            for (ContractOutstockProductEnum outstockProductEnum : ContractOutstockProductEnum.values()) {
                if (!UpdateDataTypeEnum.DETAIL.formatShow(outstockProductEnum.getShowType())) {
                    continue;
                }
                String attr = outstockProductEnum.getAttr();
                switch (outstockProductEnum) {
                    case PRODUCT:
                        json.put(attr, outstockProductEntity.getProductId());
                        break;
                    case WAREHOUSE:
                        JSONArray warehouseArr = productHelp.packegeLinkBusinessJsonArray(outstockProductEntity.getWarehouseId(),
                                warehouseNameMap.getOrDefault(outstockProductEntity.getWarehouseId(), ""), XbbRefTypeEnum.WAREHOUSE.getCode(), SaasMarkEnum.SAAS.getCode());
                        json.put(attr, warehouseArr);
                        break;
                    case NUM:
                        json.put(attr, outstockProductEntity.getProductNum());
                        break;
                    case COST:
                        json.put(attr, outstockProductEntity.getCost());
                        break;
                    case TOTAL_COST:
                        if (Objects.nonNull(outstockProductEntity.getCost()) && Objects.nonNull(outstockProductEntity.getProductNum())) {
                            json.put(attr, Arith.mul(outstockProductEntity.getProductNum(), outstockProductEntity.getCost()));
                        }
                        break;
                    case STOCK:
                        json.put(attr, stock);
                        break;
                    case MEMO:
                        json.put(attr, outstockProductEntity.getMemo());
                        break;
                    case BATCH:
                        json.put(attr, outstockProductEntity.getBatch());
                        break;
                    case PRODUCE_DATE:
                        json.put(attr, outstockProductEntity.getProduceDate());
                        break;
                    case GUARANTEE_PERIOD:
                        if (Objects.nonNull(outstockProductEntity.getGuaranteePeriod()) && !Objects.equals(outstockProductEntity.getProduceDate(), 0L)) {
                            json.put(attr, Arith.div(outstockProductEntity.getGuaranteePeriod(), TimeConstant.SECONDS_PER_DAY));
                        } else {
                            json.remove(attr);
                        }
                        break;
                    case EXPIRE_DATE:
                        if (Objects.nonNull(outstockProductEntity.getGuaranteePeriod()) && Objects.nonNull(outstockProductEntity.getProduceDate())) {
                            json.put(attr, Arith.add(outstockProductEntity.getProduceDate(), outstockProductEntity.getGuaranteePeriod()));
                        }
                        break;
                    case UNIT:
                        String unitStr = productModel.getProductUnitTextByValue(outstockProductEntity.getProductUnit(), productExplainMap.get(ProductEnum.UNIT.getAttr()));
                        json.put(attr, unitStr);
                        break;
                    case PRICE:
//                        if (Objects.nonNull(paasFormDataEntityExt)) {
//                            json.put(attr, paasFormDataEntityExt.getData().getDouble(ProductEnum.PRICE.getAttr()));
//                        }
                        if (Objects.isNull(json.getDouble(ProductEnum.PRICE.getAttr()))) {
                            json.put(attr,0D);
                        }
                        break;
                    case SELLING_PRICE:
                        json.put(attr, outstockProductEntity.getProductPrice());
                        break;
                    case DISCOUNT:
                        json.put(attr, outstockProductEntity.getDiscount());
                        break;
                    case SUBTOTAL:
                        if (Objects.nonNull(outstockProductEntity.getProductPrice()) && Objects.nonNull(outstockProductEntity.getProductNum())) {
                            json.put(attr, Arith.mul(outstockProductEntity.getProductPrice(), outstockProductEntity.getProductNum()));
                        }
                        break;
                    default:
                        break;
                }
            }
            json.put(BusinessConstant.PRODUCT_SUB_ID, outstockProductEntity.getId());
            productArray.add(json);
        }
        detailProductVO.setProductDataArr(productArray);
        return detailProductVO;
    }

    @Override
    public void formatProduct4Show3(Map<String, Double> productBatchWarehouseMap, Map<String, Double> productWarehouseMap, Map<Long, String> warehouseNameMap, List<OutstockProductEntity> outstockProductEntityList, JSONObject data, UpdateDataTypeEnum updateDataTypeEnum, Integer type, Map<Long, List<MultiUnitPricePoJo>> priceMap) throws XbbException {
        outstockModel.formatProduct4Show3(productBatchWarehouseMap, productWarehouseMap, warehouseNameMap, outstockProductEntityList, data, updateDataTypeEnum, type, priceMap);
    }

    @Override
    public JSONObject formatSingleProduct(OutstockProductEntity outstockProductEntity) {
        return outstockModel.formatSingleProduct(outstockProductEntity);
    }

    @Override
    public JSONObject formatSingleContractOutstockProduct(OutstockProductEntity outstockProductEntity) {
        return outstockModel.formatSingleContractOutstockProduct(outstockProductEntity);
    }

    @Override
    public JSONObject formatSingleProductionMaterielOutstockProduct(OutstockProductEntity entity) {
        JSONObject json = entity.getData();
        if (Objects.isNull(json) || json.isEmpty()){
            json = new JSONObject();
            for (ProductionMaterielOutstockProductEnum productionMaterielOutstockProductEnum :ProductionMaterielOutstockProductEnum.values()){
                String attr = productionMaterielOutstockProductEnum.getAttr();
                switch (productionMaterielOutstockProductEnum){
                    case PRODUCT:
                        json.put(attr,entity.getProductId());
                        break;
                    case WAREHOUSE:
                        json.put(attr,entity.getWarehouseId());
                        break;
                    case NUM:
                        json.put(attr,entity.getProductNum());
                        break;
                    case COST:
                        json.put(attr,entity.getCost());
                        break;
                    case TOTAL_COST:
                        Double cost = Objects.isNull(entity.getCost()) ? 0D: entity.getCost();
                        Double productNum = Objects.isNull(entity.getProductNum()) ? 0D: entity.getProductNum();
                        json.put(attr,Arith.mul(cost,productNum));
                        break;
                    case MEMO:
                        json.put(attr,entity.getMemo());
                        break;
                    case BATCH:
                        json.put(attr,entity.getBatch());
                        break;
                    case PRODUCE_DATE:
                        json.put(attr,entity.getProduceDate());
                        break;
                    case GUARANTEE_PERIOD:
                        json.put(attr,entity.getGuaranteePeriod());
                        break;
                    case EXPIRE_DATE:
                        if (Objects.nonNull(entity.getGuaranteePeriod()) && Objects.nonNull(entity.getProduceDate())) {
                            json.put(attr, Arith.add(entity.getProduceDate(), entity.getGuaranteePeriod()));
                        }
                        break;
                    case UNIT:
                        json.put(attr, entity.getProductUnit());
                        break;
                    case RETURN_NUM:
                        json.put(attr, entity.getInstockNum());
                        break;
                    default:
                        break;
                }
            }
        } else if (Objects.equals(json.getDouble(SelectProductEnum.GUARANTEE_PERIOD.getAttr()), 0D)) {
            if (Objects.equals(entity.getProduceDate(), 0L) || Objects.isNull(entity.getProduceDate())) {
                json.remove(SelectProductEnum.GUARANTEE_PERIOD.getAttr());
            }
        }
        json.put(ProductionMaterielOutstockProductEnum.RETURN_NUM.getAttr(),entity.getInstockNum());
        return json;
    }

    @Override
    public void generateOutStockSheet(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        Long refId = newPaasFormDataEntity.getId();
        String corpid = saasFormSaveDTO.getCorpid();
        JSONObject newData = saasFormSaveDTO.getNewData();
        Object time = newData.get(InventoryEnum.TIME.getAttr());
        Integer businessType = saasFormSaveDTO.getBusinessType();
        Map<Object, Double> costMap = saasFormSaveDTO.getCostMap();
        String outstockType = OutstockTypeEnum.getByBuisenssType(businessType);
        String productAttr = null;
        if (Objects.equals(businessType, XbbRefTypeEnum.ASSEMBLE.getCode())) {
            productAttr = AssembleEnum.OUT_PRODUCTS.getAttr();
        }else if (Objects.equals(businessType,XbbRefTypeEnum.TRANSFER.getCode())){
            productAttr = TransferEnum.PRODUCTS.getAttr();
        }else if (Objects.equals(businessType,XbbRefTypeEnum.INVENTORY.getCode())){
            productAttr = InventoryEnum.PRODUCT.getAttr();
        }
        JSONArray productArray = saasSaveHelp.formatSelectProduct4Save2(newData, productAttr);
        // 判断是否已经生成出库单

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termQuery(ParameterConstant.DEL,DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery(OutstockEnum.getEsAttr4Keyword(OutstockEnum.REF_ID), refId));
        boolQueryBuilder.filter(termQuery(OutstockEnum.getEsAttr4Keyword(OutstockEnum.TYPE), outstockType));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_OUTSTOCK.getType()));
        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.sort(new FieldSortBuilder("addTime").order(SortOrder.DESC));
        //分页
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_OUTSTOCK.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, PaasFormDataEntityExt.class);


        OutstockEntityExt outStock = new OutstockEntityExt();

        // 获取字段解释信息，并且过滤不可见字段
        PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByBusinessType(XbbRefTypeEnum.OTHER_OUTSTOCK.getCode(), corpid);
        if (Objects.isNull(paasFormExplainEntity)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
        BeanUtil.copyProperties(paasFormExplainEntity, outStock);
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);
        FieldAttrEntity linkProductField = new FieldAttrEntity();
        for (FieldAttrEntity fieldAttrEntity : explainList) {
            if (OutstockEnum.PRODUCT.getAttr().equals(fieldAttrEntity.getAttr())) {
                linkProductField = fieldAttrEntity;
                break;
            }
        }
        //如果没有生成出库单
        if (esEntities.getTotalElements() <= 0) {
            outStock.setCorpid(corpid);
            // 获取流水号
            String serialNo = saasSaveHelp.getSerialNo(explainList, paasFormExplainEntity.getFormId(), corpid);
            outStock.setSerialNo(serialNo);
            outStock.setOwnerId(newPaasFormDataEntity.getOwnerId());
            outStock.setDepartmentId(0L);
            outStock.setFlowStatus(FlowStatusEnum.NOT_NEED_APPROVAL.getType());
            outStock.setCreatorId(newPaasFormDataEntity.getCreatorId());
            JSONObject outStockData = new JSONObject();
            //公用的部分
            if (explainMap.containsKey(OutstockEnum.TIME.getAttr())) {
                String dateType = explainMap.get(OutstockEnum.TIME.getAttr()).getDateType();
                if (Objects.nonNull(time) && !Objects.equals(XbbRefTypeEnum.INVENTORY.getCode(),businessType)){
                    outStockData.put(OutstockEnum.TIME.getAttr(), Long.valueOf(time.toString()));
                }else {
                    outStockData.put(OutstockEnum.TIME.getAttr(), DateTimeUtil.getThisIntByDateType(dateType));
                }
            } else {
                if (Objects.nonNull(time) && !Objects.equals(XbbRefTypeEnum.INVENTORY.getCode(),businessType)){
                    outStockData.put(OutstockEnum.TIME.getAttr(), Long.valueOf(time.toString()));
                }else {
                    outStockData.put(OutstockEnum.TIME.getAttr(), DateTimeUtil.getTodayInt());
                }
            }
            outStockData.put(OutstockEnum.TYPE.getAttr(),outstockType);
            outStockData.put(OutstockEnum.REF_ID.getAttr(), refId);
            outStockData.put(OutstockEnum.REF_ID_LINKED_TEXT.getAttr(), newPaasFormDataEntity.getSerialNo());
            outStockData.put(OutstockEnum.OUTBOUND.getAttr(), BasicConstant.ONE);
            //需要区分一下得部分
            formatOutstockData(outStockData, newData, businessType, productArray, costMap);
            outStock.setId(null);
            outStock.setData(outStockData);
            outstockModel.save(outStock);
        } else {
            PaasFormDataEntityExt paasFormDataEntityExt = esEntities.getContent().get(BasicConstant.ZERO);
            BeanUtil.copyProperties(paasFormDataEntityExt, outStock);
        }
        outStock.getData().put(OutstockEnum.PRODUCT.getAttr(),productArray);

        // 数据联动
        DefaultAttrPoJo defaultAttr = linkProductField.getDefaultAttr();
        String defaultType = defaultAttr.getDefaultType();
        // 获取关联产品联动关系
        LinkProductRelyEntity linkProductRelyEntity = linkProductRelyModel.getByAttrAndFormIdAndSourceBusinessType(corpid, OutstockEnum.PRODUCT.getAttr(), paasFormExplainEntity.getFormId(), businessType, DelEnum.NORMAL.getDel());
        if (Objects.nonNull(defaultType) && DefaultTypeEnum.PRODUCT_DATA_RELY.getAlias().equals(defaultType) && Objects.nonNull(linkProductRelyEntity)) {
            // 源单解释
            Map<String, FieldAttrEntity> sourceExplainMap;
            // 当前表单解释
            Map<String, FieldAttrEntity> thisExplainMap;
            // 当前表单某个关联产品解释
            Map<String, FieldAttrEntity> subThisExplainMap;
            // 源单某个关联产品解释
            Map<String, FieldAttrEntity> subSourceExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            // 当前表单某个关联产品子字段与源单某个关联产品对应关系
            Map<String, String> thisToTarget = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            // 源数据表单
            PaasFormExplainEntity sourcePaasFormExplainEntity = proFormHelp.getExplainEntity(corpid, linkProductRelyEntity.getSourceFormId(), linkProductRelyEntity.getSourceBusinessType());
            List<FieldAttrEntity> sourceExplainList = JSONArray.parseArray(sourcePaasFormExplainEntity.getExplains(), FieldAttrEntity.class);
            sourceExplainMap = ExplainUtil.getExplainMapByList(sourceExplainList, null);
            // 当前表单
            thisExplainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);
            subThisExplainMap = businessProductService.getProductRelyMap(OutstockEnum.PRODUCT.getAttr(), linkProductRelyEntity, sourceExplainMap, thisExplainMap, subSourceExplainMap, thisToTarget);
            for (Object o : productArray) {
                JSONObject productData = (JSONObject) o;
                if (!thisToTarget.isEmpty()) {
                    JSONObject thisData = businessProductService.formatThisFormData(subThisExplainMap, thisToTarget, productData);

                    for (int i = 0; i < productArray.size(); i++) {
                        JSONObject jsonObject = productArray.getJSONObject(i);
                        if (Objects.equals(jsonObject.getLongValue(BusinessConstant.REF_PRODUCT_ID), productData.getLongValue(BusinessConstant.REF_PRODUCT_ID))) {
                            jsonObject.putAll(thisData);
                            break;
                        }
                    }
                }
            }
        }

        SaasFormSaveDTO outstockSaasFormSaveDTO = new SaasFormSaveDTO();
        BeanUtil.copyProperties(saasFormSaveDTO,outstockSaasFormSaveDTO);
        outstockSaasFormSaveDTO.setNewData(outStock.getData());
        outstockSaasFormSaveDTO.setNewPaasFormDataEntity(outStock);
        outstockSaasFormSaveDTO.setIsNew(true);
        outstockSaasFormSaveDTO.setBusinessType(XbbRefTypeEnum.OTHER_OUTSTOCK.getCode());
        afterSave(outstockSaasFormSaveDTO);
    }

    /**
     * 自动生成出库单时格式化出库单保存时得数据
     * @param outStockData 保存的数据
     * @param businessType
     * @param newData 前端传的数据
     */
    private void formatOutstockData(JSONObject outStockData, JSONObject newData, Integer businessType, JSONArray productArray, Map<Object,Double> costMap) throws XbbException {
        RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(businessType);
        switch (redundantTemplateTypeEnum){
            case TRANSFER:
                outStockData.put(OutstockEnum.WAREHOUSE_ID.getAttr(), FastJsonHelper.getLongOrDefaultFromFormData(newData, TransferEnum.OUT_WAREHOUSE_ID.getAttr(), 0L));
                outStockData.put(OutstockEnum.WAREHOUSE_ID_LINKED_TEXT.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(newData, TransferEnum.OUT_WAREHOUSE_ID_LINKED_TEXT.getAttr(), ""));
                outStockData.put(OutstockEnum.MEMO.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(newData, TransferEnum.MEMO.getAttr(), ""));
                outStockData.put(OutstockEnum.PRODUCT.getAttr(), newData.getJSONArray(TransferEnum.PRODUCTS.getAttr()));
                for (int i = 0; i < productArray.size(); i++) {
                    JSONObject jsonObject = productArray.getJSONObject(i);
                    jsonObject.put(OutstockProductEnum.WAREHOUSE.getAttr(), FastJsonHelper.getLongOrDefaultFromFormData(newData, TransferEnum.OUT_WAREHOUSE_ID.getAttr(), 0L));
                    jsonObject.put("warehouseName", FastJsonHelper.getStringOrDefaultFromFormData(newData, TransferEnum.OUT_WAREHOUSE_ID_LINKED_TEXT.getAttr(), ""));
                    if (StringUtil.isNotEmpty(jsonObject.getString(SelectProductEnum.BATCH.getAttr()))) {
                        jsonObject.put(SelectProductEnum.COST.getAttr(), costMap.getOrDefault(formDataValidateProductHelp.getBatchKey(jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr()), jsonObject.getLong(SelectProductEnum.WAREHOUSE.getAttr()), jsonObject.getString(SelectProductEnum.BATCH.getAttr()), jsonObject.getLong(SelectProductEnum.PRODUCE_DATE.getAttr()), FastJsonHelper.getLongOrDefaultFromFormData(jsonObject, SelectProductEnum.GUARANTEE_PERIOD.getAttr(), 0L) * TimeConstant.SECONDS_PER_DAY), 0D));
                    }else {
                        jsonObject.put(SelectProductEnum.COST.getAttr(), costMap.getOrDefault(jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr())+ "_" + jsonObject.get(OutstockProductEnum.WAREHOUSE.getAttr()), 0D));
                    }
                    Double rate = jsonObject.getDouble(SelectProductEnum.RATE.getAttr());
                    if (Objects.nonNull(rate)) {
                        jsonObject.put(SelectProductEnum.BUSINESS_COST.getAttr(), Arith.mul(jsonObject.getDouble(SelectProductEnum.COST.getAttr()), rate));
                    }
                    jsonObject.put(SelectProductEnum.TOTAL_COST.getAttr(), Arith.mul(jsonObject.getDouble(SelectProductEnum.COST.getAttr()), jsonObject.getDouble(SelectProductEnum.NUM.getAttr())));
                }
                break;
            case ASSEMBLE:
                outStockData.put(OutstockEnum.WAREHOUSE_ID.getAttr(), FastJsonHelper.getLongOrDefaultFromFormData(newData, AssembleEnum.OUT_WAREHOUSE_ID.getAttr(), 0L));
                outStockData.put(OutstockEnum.WAREHOUSE_ID_LINKED_TEXT.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(newData, AssembleEnum.OUT_WAREHOUSE_ID_LINKED_TEXT.getAttr(), ""));
                outStockData.put(OutstockEnum.MEMO.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(newData, AssembleEnum.MEMO.getAttr(), ""));
                outStockData.put(OutstockEnum.PRODUCT.getAttr(), newData.getJSONArray(AssembleEnum.OUT_PRODUCTS.getAttr()));
                break;
            case INVENTORY:
                outStockData.put(OutstockEnum.WAREHOUSE_ID.getAttr(), FastJsonHelper.getLongOrDefaultFromFormData(newData, InventoryEnum.WAREHOUSE_ID.getAttr(), 0L));
                outStockData.put(OutstockEnum.WAREHOUSE_ID_LINKED_TEXT.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(newData, InventoryEnum.WAREHOUSE_ID_LINKED_TEXT.getAttr(), ""));
                outStockData.put(OutstockEnum.MEMO.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(newData, InventoryEnum.MEMO.getAttr(), ""));
                outStockData.put(OutstockEnum.PRODUCT.getAttr(), newData.getJSONArray(InventoryEnum.PRODUCT.getAttr()));
                for (int i = 0; i < productArray.size(); i++) {
                    JSONObject jsonObject = productArray.getJSONObject(i);
                    jsonObject.put(OutstockProductEnum.WAREHOUSE.getAttr(), FastJsonHelper.getLongOrDefaultFromFormData(newData, OutstockEnum.WAREHOUSE_ID.getAttr(), 0L));
                    jsonObject.put("warehouseName", FastJsonHelper.getStringOrDefaultFromFormData(newData, InventoryEnum.WAREHOUSE_ID_LINKED_TEXT.getAttr(), ""));
                    if (StringUtil.isNotEmpty(jsonObject.getString(SelectProductEnum.BATCH.getAttr()))) {
                        jsonObject.put(SelectProductEnum.COST.getAttr(), costMap.getOrDefault(formDataValidateProductHelp.getBatchKey(jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr()), jsonObject.getLong(SelectProductEnum.WAREHOUSE.getAttr()), jsonObject.getString(SelectProductEnum.BATCH.getAttr()), jsonObject.getLong(SelectProductEnum.PRODUCE_DATE.getAttr()), FastJsonHelper.getLongOrDefaultFromFormData(jsonObject, SelectProductEnum.GUARANTEE_PERIOD.getAttr(), 0L) * TimeConstant.SECONDS_PER_DAY), 0D));
                    }else {
                        jsonObject.put(SelectProductEnum.COST.getAttr(), costMap.getOrDefault(jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr())+ "_" + jsonObject.get(OutstockProductEnum.WAREHOUSE.getAttr()), 0D));
                    }
                    jsonObject.put(SelectProductEnum.TOTAL_COST.getAttr(), Arith.mul(jsonObject.getDouble(SelectProductEnum.COST.getAttr()), jsonObject.getDouble(SelectProductEnum.NUM.getAttr())));
                }
                break;
            default:
                break;
        }
    }

//    /**
//     * 获取出库单产品
//     *
//     * @param businessProductListDTO 入参
//     * @param jsonObject 数据对象
//     * @author chaoxiong.lei
//     * @Date 14:37 2019/3/5
//     * @since v1.0
//     * @return BusinessProductListVO，属性product包含了出库单关联产品，返回给前端的格式
//     **/
  /*  @Override
    public BusinessProductListVO getOutstockProductList(BusinessProductListDTO businessProductListDTO, JSONObject jsonObject) throws XbbException {
        String corpid = businessProductListDTO.getCorpid();
        Long outstockId = businessProductListDTO.getDataId();
        boolean detailGet = businessProductListDTO.getDetailGet();
        Integer businessType = businessProductListDTO.getBusinessType();
        OutstockEntityExt outstockEntityExt;

        // 获取出库单关联产品
        List<OutstockProductEntity> outstockProductList = new ArrayList<>();
        List<ProductStockInfoEntity> productStockInfoList = new ArrayList<>();
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, corpid);
        modelMap.put("outWarehouseId", outstockId);
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put(ParameterConstant.PAGE, businessProductListDTO.getPage());
        PageHelper pageHelper = PageHelperUtil.getPageHelper(modelMap, outstockProductModel, businessProductListDTO.getPageSize());
        if (businessProductListDTO.getForProcess() && jsonObject != null) {
            outstockEntityExt = new OutstockEntityExt();
            outstockEntityExt.setData(jsonObject);
            JSONArray productArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(saasUpdateHelp.getJsonObjectOrDefaultFromFormData(jsonObject, OutstockEnum.PRODUCT.getAttr(), new JSONObject()), StringConstant.PRODUCT_LIST, new JSONArray());
            Map<Long, ProductEntityExt> productMap = getProductMap(new HashSet<>(), corpid, productArray);
            getProductList(corpid, outstockProductList, productStockInfoList, productArray, productMap);
        } else {
            outstockProductList = (List<OutstockProductEntity>)PageHelperUtil.getEntityList(modelMap, pageHelper, outstockProductModel);
            outstockEntityExt = outstockModel.getByKey(outstockId, corpid);
        }
        Integer type = saasUpdateHelp.getIntegerFromFormData(outstockEntityExt.getData(), OutstockEnum.TYPE.getAttr());

        // 根据idIn参数获取对应的产品数据
        Set<Long> productIdIn = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        productIdIn.add(-1L);
        List<Long> outstockProductIds = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        outstockProductIds.add(-1L);
        List<Long> warehouseIds = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        warehouseIds.add(-1L);
        Set<String> warehouseKeySet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (OutstockProductEntity entity : outstockProductList) {
            productIdIn.add(entity.getProductId());
            outstockProductIds.add(entity.getId());
            warehouseIds.add(entity.getWarehouseId());
            warehouseKeySet.add(entity.getProductId() + "_" + entity.getWarehouseId());
        }

        // 出库单产品对应产品信息
        Map<Long, PaasFormDataEntityExt> productMap = productService.getProductMapByIdIn(productIdIn,corpid, DelEnum.NORMAL);

        // 出库单产品对应仓库信息
        Map<Long, JSONObject> warehouseMap = warehouseModel.findWarehouseObjMapByIdIn(warehouseIds, corpid);

        // 参数集合
        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        params.put("corpid", corpid);
        params.put("del", 0);
//        params.put("productIdIn", productIdIn);
//        params.put("warehouseIdIn", warehouseIds);
        params.put("warehouseKeyIn",warehouseKeySet);
        List<ProductWarehouseEntity> productWarehouseEntityList = productWarehouseModel.findEntitysWithWarehouseChecked(params,null);

        // 出库单产品库存信息
        if (jsonObject == null) {
            productStockInfoList = productStockInfoModel.getByRefIdInAndRefType(outstockProductIds, XbbRefTypeEnum.OUTSTOCK_PRODUCT.getCode(), corpid);
        }

        // 用于存放当前启用的产品模板解释的map
        Map<String, FieldAttrEntity> nowProductExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, FieldAttrEntity> nowStockProductExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        saasAddHelp.getRelativeProductExplainsFromDB(corpid, nowProductExplainMap, nowStockProductExplainMap);

        JSONObject productFinalObj = new JSONObject();
        JSONArray productArray = new JSONArray();
        // 将产品存入map中，key为产品的sort值，用于产品排序
        Map<Integer, JSONObject> productSortMap = new TreeMap<>();
        BusinessProductListVO businessProductListVO = new BusinessProductListVO();
        // 与productList同级，返回对应关联产品的attr
        String attrStr = OutstockEnum.PRODUCT.getAttr();
        // 得到该公司设置的金额小数精度
//        Integer amountPrecision = companyConfigService.getAmountPrecision(corpid);
        // 价格、成本、数量小数精度
        FieldAttrEntity priceFieldAttrEntity = new FieldAttrEntity();
        FieldAttrEntity costFieldAttrEntity = new FieldAttrEntity();
        FieldAttrEntity numFieldAttrEntity = new FieldAttrEntity();
        if(nowProductExplainMap.containsKey(ProductEnum.PRICE.getSaasAttr())) {
            priceFieldAttrEntity = nowProductExplainMap.get(ProductEnum.PRICE.getSaasAttr());
        }
        if(nowProductExplainMap.containsKey(ProductEnum.COST.getSaasAttr())) {
            costFieldAttrEntity = nowProductExplainMap.get(ProductEnum.COST.getSaasAttr());
        }
        if(nowProductExplainMap.containsKey(ProductEnum.STOCK.getSaasAttr())) {
            numFieldAttrEntity = nowProductExplainMap.get(ProductEnum.STOCK.getSaasAttr());
        }
        Integer amountPrecision = priceFieldAttrEntity.getAccuracy();
        Integer costPrecision = costFieldAttrEntity.getAccuracy();
        Integer numPrecision = numFieldAttrEntity.getAccuracy();
        FormConfigEntity formConfigEntity = formConfigModel.getEntityByBusinessType(corpid, XbbRefTypeEnum.OUTSTOCK.getCode(), FormConfigEnum.OUTSTOCK_DISPLAY_SALE_PRICE.getConfig());
        Integer showSalePriceFlag = 0;
        if (Objects.nonNull(formConfigEntity) && Objects.equals(formConfigEntity.getConfigValue(), "1")) {
            showSalePriceFlag = 1;
        }
        // 成本字段是否可见
        boolean hideCost = false;
        for (OutstockProductEntity outstockProduct : outstockProductList) {
            Long productId = outstockProduct.getProductId();
            Long warehouseId = outstockProduct.getWarehouseId();

            if (!hideCost) {
                ProductEntityExt childProduct = productModel.getByKey(productId, corpid);
                if (childProduct != null) {
                    Long parentId = childProduct.getData().getLong(ProductEnum.PARENT_ID.getAttr());
                    PaasFormDataEntityExt paasFormDataEsEntity = productModel.getByKey(parentId, corpid);
                    if (paasFormDataEsEntity != null) {
                        //协同团队
                        Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        userTeamService.getUserIdMap(Collections.singletonList(parentId), corpid, XbbRefTypeEnum.PRODUCT.getCode(), false, mainUserMap, coUserMap);
                        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
                        BeanUtil.copyProperties(businessProductListDTO, handlerExplainDTO);
                        handlerExplainDTO.setCreatorId(paasFormDataEsEntity.getCreatorId());
                        handlerExplainDTO.setOwnerId(mainUserMap.getOrDefault(paasFormDataEsEntity.getDataId(), new ArrayList<>()));
                        handlerExplainDTO.setCoUserId(coUserMap.getOrDefault(paasFormDataEsEntity.getDataId(), new ArrayList<>()));
                        handlerExplainDTO.setExplainList(new ArrayList<>(nowProductExplainMap.values()));
                        hideCost = ExplainUtil.isFieldNeedHide(nowProductExplainMap.getOrDefault(ProductEnum.COST.getSaasAttr(), new FieldAttrEntity()), handlerExplainDTO);
                    }
                }
            }

            OutstockProductEntityExt outstockProductExt = new OutstockProductEntityExt();
            BeanUtil.copyProperties(outstockProduct, outstockProductExt);
            // 格式化规格
            String specification = specificationModel.joinSpecification(outstockProduct.getProductSpecification());
            outstockProductExt.setProductSpecification(specification);
            // 设置仓库信息
            if (warehouseId != null) {
                JSONObject warehouseObj = warehouseMap.get(warehouseId);
                outstockProductExt.setWarehouseObj(warehouseObj);
            }

            Double productStock = 0.0;
            String batch = "";
            // 获取对应的产品信息
            PaasFormDataEntityExt product = productMap.get(productId);
            if (product != null) {
                JSONObject productDataList = product.getData();
                outstockProductExt.setBarcode(productDataList.getString(ProductEnum.BARCODE.getAttr()));
                // 产品的总库存
                productStock = productDataList.getDouble(ProductEnum.STOCK.getAttr());
                outstockProductExt.setImageUrlArray(productDataList.getJSONArray(ProductEnum.PRODUCT_IMGS.getAttr()));
            } else {
                throw new XbbException(ProductErrorCodeEnum.API_ERROR_205040, ProductErrorCodeEnum.API_ERROR_205040.getMsg());
            }

            for (ProductWarehouseEntity productWarehouseEntity : productWarehouseEntityList) {
                if (Objects.equals(productWarehouseEntity.getWarehouseId(), warehouseId) && Objects.equals(productWarehouseEntity.getProductId(), productId)) {
                    productStock = productWarehouseEntity.getNum();
                    break;
                }
            }

            // 设置库存信息
            outstockProductExt.setStock(productStock);

            if (Objects.equals(OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode(), type)) {
                // 构建销售出库返回字段
                businessType = XbbRefTypeEnum.CONTRACT.getCode();
            }
            // 构建格式化出库产品的DTO
            FormatOutstockProductDTO formatOutstockProductDTO = new FormatOutstockProductDTO();
            BeanUtil.copyProperties(businessProductListDTO, formatOutstockProductDTO);
            formatOutstockProductDTO.setBusinessType(businessType);
//            outstockProductExt.setProductStockInfoEntity(productStockInfo);
            formatOutstockProductDTO.setOutstockProductExt(outstockProductExt);
            formatOutstockProductDTO.setNowProductExplainMap(nowProductExplainMap);
            formatOutstockProductDTO.setNowStockProductExplainMap(nowStockProductExplainMap);
            JSONObject productObj = getFormatProductJsonArray(formatOutstockProductDTO);
            if (Objects.equals(OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode(), type)) {
                // 构建销售出库返回字段
                PaasFormDataEntityExt paasFormDataEsEntity = new PaasFormDataEntityExt();
                BeanUtil.copyProperties(product, paasFormDataEsEntity);
                paasFormDataEsEntity.setData(product.getData());
                contractService.addSalePriceAndDiscountExplains(productObj, outstockProductExt, paasFormDataEsEntity, amountPrecision, showSalePriceFlag);
            }
            productSortMap.put(outstockProductExt.getSort(), productObj);
        }
        // 产品排序
        productArray.addAll(productSortMap.values());
        productFinalObj.put(StringConstant.PRODUCT_LIST, productArray);
        productFinalObj.put(StringConstant.REDUNDANT_FIELD_ATTR_BEGIN_FLAG, attrStr);
        if (Objects.equals(OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode(), type)) {
            List<FieldAttrEntityExt> fieldAttrEntityExtList = new ArrayList<>();
            List<FieldAttrEntityExt> fieldAttrEntityList = saasGetHelp.getSelectProductExplains(XbbRefTypeEnum.OUTSTOCK, businessType, corpid, OutstockEnum.PRODUCT.getAttr());
            for (FieldAttrEntityExt fieldAttrEntity : fieldAttrEntityList) {
                FieldAttrEntityExt fieldAttrEntityExt = new FieldAttrEntityExt();
                BeanUtil.copyProperties(fieldAttrEntity, fieldAttrEntityExt);
                String attr = fieldAttrEntityExt.getAttr();
                if (Objects.equals(attr, RelativeProductEnum.SALE_PRODUCT_PRICE.getSaasAttr()) || Objects.equals(attr, RelativeProductEnum.SALE_SUBTOTAL.getSaasAttr())
                        || Objects.equals(attr, RelativeProductEnum.PRODUCT_PRICE.getSaasAttr()) || Objects.equals(attr, RelativeProductEnum.SALE_DISCOUNT.getSaasAttr())) {
                    fieldAttrEntityExt.setShowSalePrice(showSalePriceFlag);
                }
                // 销售出库单价属于销售出库特殊字段，特殊saasAttr(佳华说的)
                if (Objects.equals(attr, RelativeProductEnum.PRODUCT_PRICE.getSaasAttr())) {
                    fieldAttrEntityExt.setAttr(OutstockSaleRelativeConstantEnum.PRICE.getAlias());
                    fieldAttrEntityExt.setSaasAttr(OutstockSaleRelativeConstantEnum.PRICE.getAlias());
                }
                fieldAttrEntityExtList.add(fieldAttrEntityExt);
            }
            productFinalObj.put(BusinessConstant.EXPLAINS, fieldAttrEntityExtList);
        } else {
            productFinalObj.put(BusinessConstant.EXPLAINS, saasUpdateHelp.getSelectProductExplains(XbbRefTypeEnum.OUTSTOCK, corpid, OutstockEnum.PRODUCT.getAttr()));
        }

        // 成本字段是否启用
        boolean isCostOpen = false;
        FieldAttrEntity costField = nowProductExplainMap.get(ProductEnum.COST.getSaasAttr());
        if (costField != null && Objects.equals(costField.getIsOpen(), 1) && Objects.equals(costField.getVisible(), 1)) {
            isCostOpen = true;
        }

        JSONObject otherObj = setOutstockTotalAttr(corpid, outstockEntityExt, outstockProductList, showSalePriceFlag, hideCost, isCostOpen, amountPrecision, costPrecision, numPrecision);
        productFinalObj.put(BusinessConstant.OTHERS, otherObj);
        businessProductListVO.setProduct(productFinalObj);
        businessProductListVO.setPageHelper(pageHelper);
        return businessProductListVO;
    }*/

    public JSONObject setOutstockTotalAttr(String corpid, OutstockEntityExt outstockEntity, List<OutstockProductEntity> outstockProductList, Integer showSalePriceFlag, boolean hideCost, boolean isCostOpen,
                                           Integer amountPrecision, Integer costPrecision, Integer numPrecision) {
        JSONObject othersObj = new JSONObject();
        Map<String, Double> productInfo = getOutstockProductsInfo(outstockEntity, outstockProductList);
        Integer type = outstockEntity.getData().getInteger(OutstockEnum.TYPE.getAttr());
        othersObj.put("outNumTotal", attrDecimalPrecisionHelper.setPrecision(productInfo.get("outNumTotal"), numPrecision));
        if (isCostOpen) {
            othersObj.put("outProductCostTotal", attrDecimalPrecisionHelper.setPrecision(productInfo.get("outProductCostTotal"), costPrecision));
        }
        othersObj.put("hideCost", hideCost);

        if (Objects.equals(type, OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode()) && Objects.equals(showSalePriceFlag, 1)) {
            // 销售出库，开关开启
            Double productPriceTotal = productInfo.get("priceTotal");
            othersObj.put("priceTotal", productPriceTotal == null ? "--" : attrDecimalPrecisionHelper.setPrecision(productPriceTotal, amountPrecision));
        }
        return othersObj;
    }

    public Map<String, Double> getOutstockProductsInfo(OutstockEntityExt outstockEntity, List<OutstockProductEntity> outstockProductList) {
        Map<String, Double> productInfo = new HashMap<>(16);
        Integer type = outstockEntity.getData().getInteger(OutstockEnum.TYPE.getAttr());
        Double outNumTotal = 0D;
        Double outProductCostTotal = 0D;
        Double priceTotal = null;
        // 默认显示售价总计
        if (Objects.equals(type, OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
            priceTotal = 0D;
        }
        Double rate;
        for (OutstockProductEntity entity : outstockProductList) {
            rate = entity.getRate() == null ? 1D : entity.getRate();
            Double productNum = entity.getProductNum() == null ? 0D : entity.getProductNum();
            Double cost = entity.getCost() == null ? 0D : entity.getCost();
            outNumTotal = Arith.add(outNumTotal, Arith.div(productNum,rate));
            outProductCostTotal = Arith.add(outProductCostTotal, Arith.mul(productNum, cost));
            if (Objects.equals(type, OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
                // 出库类型是销售出库
                if (Objects.nonNull(entity.getProductPrice())) {
                    // 销售出库产品的老数据没有保存售价值，则显示"- -"
                    if (Objects.nonNull(entity.getPriceData()) && !entity.getPriceData().isEmpty()) {
                        entity.setProductPrice(entity.getPriceData().getDouble(ContractOutstockProductEnum.SELLING_PRICE.getAttr()));
                    }
                    priceTotal = Arith.add(priceTotal, Arith.mul(entity.getProductPrice(), Arith.div(entity.getProductNum(), rate)));
                }
            }
        }
        productInfo.put("outNumTotal", outNumTotal);
        productInfo.put("outProductCostTotal", outProductCostTotal);
        if (Objects.equals(type, OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
            productInfo.put("priceTotal", priceTotal);
        }
        return productInfo;
    }

    @Override
    public OutstockDeleteBatchVO deleteBatch(OutstockDeleteBatchDTO outstockDeleteBatchDTO) throws XbbException {
        OutstockDeleteBatchVO outstockDeleteBatchVO = new OutstockDeleteBatchVO();
        String corpid = outstockDeleteBatchDTO.getCorpid();
        List<OutstockProductEntity> outstockProductList = null;
        boolean isRollBack = false;
        Integer businessType = outstockDeleteBatchDTO.getBusinessType();
        //被锁的入库单id
        List<Long> lackIdList;
        try {
            String limit = paasRedisHelper.getValue(RedisPrefixConstant.PRODUCE_STOCK_FLOW, corpid);
            if (StringUtil.isNotEmpty(limit)) {
                throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212036);
            }
            lackIdList = checkRedisKey(corpid,outstockDeleteBatchDTO.getDataIdList());
//            if (outstockDeleteBatchDTO.getDataIdList().isEmpty()){
            lackMsg(lackIdList,corpid);
//            }
            List<Long> outstockIdIn = outstockDeleteBatchDTO.getDataIdList();
            Map<String, Object> param = BeanUtil.convertBean2Map(outstockDeleteBatchDTO, true);
            param.put("idIn", outstockIdIn);
            param.put("del", 0);
            List<OutstockEntityExt> outstockList = outstockModel.findEntitys(param);
            if (Objects.isNull(outstockList)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
            }
            SettleAccountsEntity accountsEntity = settleAccountsModel.getLastSettleAccounts(corpid);
            for (OutstockEntityExt outstockEntityExt : outstockList) {
                Integer date = outstockEntityExt.getData().getInteger(OutstockEnum.TIME.getAttr());
                //结账中校验
                String redisHelperValue = paasRedisHelper.getValue(RedisPrefixConstant.SETTLE_ACCOUNTS, corpid);
                if (StringUtil.isNotEmpty(redisHelperValue)) {
                    if (date <= DateTimeUtil.getTodayEndInt(Long.valueOf(redisHelperValue))){
                        throw new XbbException(SettleAccountErrorCodeEnum.API_ERROR_254007);
                    }
                }
                //校验日期是否受结账限制
                if (Objects.nonNull(accountsEntity) && Objects.nonNull(accountsEntity.getCheckOutTime())) {
                    if (date <= DateTimeUtil.getTodayEndInt(accountsEntity.getCheckOutTime())) {
                        throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212032);
                    }
                }
            }
            //库存解绑校验
            warehouseBoundCheck(outstockList,outstockIdIn,corpid);
            // 出库单删除校验
            //返回值是关闭了批次号管理的产品
            Set<Long> disableBatchProducts = checkOutstockDelete(corpid, outstockList, outstockDeleteBatchDTO.getBusinessType());

            if(!outstockIdIn.isEmpty()) {
                //判断销售出库单/出库发货单是否有关联应收，并且应收是否有回款单
                List<PaasFormDataEntityExt> paymentList = paymentService.checkCanDelPayment(corpid, ModelTypeEnum.OUTSTOCK.getXbbRefTypeEnum(), outstockIdIn);
                if (!CollectionsUtil.isEmpty(paymentList)) {
                    List<Long> errorDataId = new ArrayList<>();
                    List<String> errorDataNo = new ArrayList<>();
                    Set<String> errorTypeSet = new HashSet<>();
                    List<PaasFormDataEntityExt> receivablesEntityExt = receivablesHelper.checkReceivablesWhetherCanDel(paymentList, corpid, errorDataId, errorDataNo, errorTypeSet);
                    if (CollectionsUtil.isEmpty(errorDataId)) {
                        OperateTypeEnum operateTypeEnum = OperateTypeEnum.DELETE;
                        if (Objects.equals(1, outstockDeleteBatchDTO.getIsBusinessRule())) {
                            operateTypeEnum = OperateTypeEnum.RULE_DELETE;
                        }
                        receivablesHelper.delReceivablesHandle(receivablesEntityExt, operateTypeEnum, outstockDeleteBatchDTO.getUserId(), outstockDeleteBatchDTO.getLoginUserName(), corpid, outstockDeleteBatchDTO.getHttpHeader());
                    } else {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001.getCode(), I18nMessageUtil.getMessage(ErrorMessageConstant.RECEIVABLES_HAS_PAYMENT_SHEET));
                    }
                }
                if(BasicConstant.ONE.equals(outstockDeleteBatchDTO.getSingleFlag()) && BasicConstant.ONE.equals(outstockIdIn.size())){
                    outstockModel.deleteByKey(outstockIdIn.get(0),corpid);
                } else {
                    // 出库单ES数据删除等待问题。将刷新策略改为不等待策略，如果后面的代码再次查询出库单列表，则在查询条件中添加【must not in被删除的出库单id列表】的条件
                    outstockModel.deleteBatchImmediately(outstockIdIn, corpid, WriteRequest.RefreshPolicy.NONE);
                }
                outstockDeleteBatchVO.setDeleteIds(outstockIdIn);
            }

            List<Long> returnedPurchaseOutstock = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> inventoryOutstock = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> transferOutstock = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> materielOutstockIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<Long, OutstockEntityExt> materielOutstockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<OutstockEntityExt> contractOutstockList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<OutstockEntityExt> workOrderOutstockList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> contractOutstockIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Integer type = null;
            for (OutstockEntityExt item : outstockList) {
                JSONObject jsonObject = item.getData();
                Long refId = jsonObject.getLong(OutstockEnum.REF_ID.getAttr());
                if (Objects.isNull(refId)) {
                    type = OutstockTypeEnum.OTHER_OUTSTOCK.getCode();
                    continue;
                }
                type = jsonObject.getInteger(OutstockEnum.TYPE.getAttr());
                OutstockTypeEnum outstockTypeEnum = OutstockTypeEnum.getByCode(type);
                switch (outstockTypeEnum) {
                    case RETURNED_PURCHASE_OUTSTOCK:
                        returnedPurchaseOutstock.add(refId);
                        break;
                    case CONTRACT_OUTSTOCK:
                        contractOutstockList.add(item);
                        contractOutstockIdList.add(item.getId());
                        break;
                    case INVENTORY_OUTSTOCK:
                        inventoryOutstock.add(refId);
                        break;
                    case TRANSFER_OUTSTOCK:
                        transferOutstock.add(refId);
                        break;
                    case MATERIEL_OUTSTOCK:
                        materielOutstockIdIn.add(refId);
                        // TODO 问题：同一个生产单多次物料出库，则materielOutstockMap会出现相同的refId覆盖数据的情况
                        materielOutstockMap.put(refId, item);
                        break;
                    case WORK_ORDER_OUTSTOCK:
                        workOrderOutstockList.add(item);
                        break;
                    default:
                        break;
                }
            }

            // 删除出库单关联产品
            OutstockProductDeleteBatchDTO outstockProductDeleteBatchDTO = new OutstockProductDeleteBatchDTO();
            BeanUtil.copyProperties(outstockDeleteBatchDTO, outstockProductDeleteBatchDTO);
            outstockProductDeleteBatchDTO.setOutstockIdIn(outstockIdIn);
            OutstockProductDeleteBatchVO outstockProductDeleteBatchVO = outstockProductService.deleteBatchByOutstockIdIn(outstockProductDeleteBatchDTO);
            if (Objects.isNull(outstockProductDeleteBatchVO)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
            }
            outstockProductList = outstockProductDeleteBatchVO.getOutstockProductList();
            boolean isCheck = concurrentLockAspect.checkStock(corpid);
            if (isCheck){
                // 删除出库单超发出库校验
                concurrentLockAspect.delOutstockCheck(corpid,outstockProductList);
            }
            isRollBack = true;
            // 重置采购退货单关联出库单id
            if (!returnedPurchaseOutstock.isEmpty()) {
                BoolQueryBuilder boolQueryBuilder = boolQuery();
                boolQueryBuilder
                        .filter(termQuery("corpid.keyword", corpid))
                        .filter(termQuery("del", 0))
                        .filter(termsQuery(FieldTypeEnum.DATAID.getAlias(),returnedPurchaseOutstock));
                    List<PaasFormDataEntity> returnedPurchaseEntitys = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_RETURNED_PURCHASE, boolQueryBuilder, PaasFormDataEntity.class, Arrays.asList(FieldTypeEnum.DATAID.getAlias(), ReturnedPurchaseEnum.getAttrConnectData(ReturnedPurchaseEnum.RETURNED_STATUS)));
                    Map<Long,String> returnedPurchaseMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    returnedPurchaseEntitys.forEach(item -> returnedPurchaseMap.put(item.getDataId(),item.getData().getString(ReturnedPurchaseEnum.RETURNED_STATUS.getAttr())));
                Set<Long> lineReturnedPurchaseIdList = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                List<Long> mergeReturnedPurchaseIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Integer outstockType = null;
                for(OutstockEntityExt outstockEntityExt : outstockList){
                    JSONObject data = outstockEntityExt.getData();
                    outstockType = data.getInteger(OutstockEnum.TYPE.getAttr());
                    if(Objects.equals(outstockType, OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                        Long outstockId = outstockEntityExt.getId();
                        Long returnedPurchaseId = data.getLong(OutstockEnum.REF_ID.getAttr());
                        for(OutstockProductEntity outstockProductEntity : outstockProductList) {
                            if (Objects.equals(outstockProductEntity.getOutWarehouseId(), outstockId)) {
                                if (!Objects.isNull(outstockProductEntity.getRefProductId())) {
                                    lineReturnedPurchaseIdList.add(returnedPurchaseId);
                                } else {
                                    mergeReturnedPurchaseIdList.add(returnedPurchaseId);
                                }
                            }
                        }
                    }
                }
                List<ReturnedPurchaseUpdateDTO> returnedPurchaseList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if(!lineReturnedPurchaseIdList.isEmpty()){
                    //新数据修改采购退货产品的已入库数量
                    Set<Long> returnedStatusSet = updateReturnedPurchaseProductOutNumBatch(lineReturnedPurchaseIdList, corpid,outstockIdIn);
                    //出库单删除,对应采购退货单则修改为未出库完成
                    lineReturnedPurchaseIdList.forEach((item)->{
                        ReturnedPurchaseUpdateDTO returnedPurchaseUpdateDTO = new ReturnedPurchaseUpdateDTO();
                        returnedPurchaseUpdateDTO.setId(item);
                        JSONObject data = new JSONObject();
                        // TODO 问题：现在采购退货单可以关联多个采购退货出库单，所以删除一个出库单后并不能将关联关系直接清空，可能还有关联的其他出库单
                        data.put(ReturnedPurchaseEnum.OUTSTOCK_ID.getAttr(), "");
                        data.put(ReturnedPurchaseEnum.STATUS.getAttr(), ReturnedPurchaseStatusEnum.WAIT_OUTSTOCK.getStatus());
                        if (returnedPurchaseMap.containsKey(item)) {
                            String returnedStatus = returnedPurchaseMap.get(item);
                            //先要判断退货状态是否已关闭
                            if (!Objects.equals(returnedStatus, ReturnedStatusEnum.CLOSED.getCode())) {
                                if (returnedStatusSet.contains(item)) {
                                    data.put(ReturnedPurchaseEnum.RETURNED_STATUS.getAttr(),ReturnedStatusEnum.UNRETURNED.getCode());
                                }else {
                                    data.put(ReturnedPurchaseEnum.RETURNED_STATUS.getAttr(),ReturnedStatusEnum.DELIVERED.getCode());
                                }
                            }
                        }
                        returnedPurchaseUpdateDTO.setData(data);
                        returnedPurchaseList.add(returnedPurchaseUpdateDTO);
                    });
                }
                if(!mergeReturnedPurchaseIdList.isEmpty()){
                    BoolQueryBuilder outstockQueryBuilder = boolQuery();
                    outstockQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                    outstockQueryBuilder.filter(termQuery(OutstockEnum.getEsAttr4Keyword(OutstockEnum.TYPE), OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode()));
                    outstockQueryBuilder.filter(termsQuery(OutstockEnum.getEsAttr4Keyword(OutstockEnum.REF_ID), new ArrayList<>(mergeReturnedPurchaseIdList)));
                    outstockQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                    List<PaasFormDataEntityExt> returnPurchaseoutstockList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OUTSTOCK, outstockQueryBuilder, PaasFormDataEntityExt.class, Arrays.asList(FieldTypeEnum.DATAID.getAlias(), ReturnedPurchaseOutstockEnum.getAttrConnectData(ReturnedPurchaseOutstockEnum.REF_ID)));
                    Set<Long> returnedPurchaseIds = new HashSet<>();
                    //老数据如果查到采购退货单下有其他出库单，则代表部分出库
                    if (!returnPurchaseoutstockList.isEmpty()) {
                        returnPurchaseoutstockList.forEach(item -> returnedPurchaseIds.add(item.getData().getLong(ReturnedPurchaseOutstockEnum.REF_ID.getAttr())));
                    }
                    //旧的数据采购退料单和采购退货出库是一对一
                    mergeReturnedPurchaseIdList.forEach((item)->{
                        ReturnedPurchaseUpdateDTO returnedPurchaseUpdateDTO = new ReturnedPurchaseUpdateDTO();
                        returnedPurchaseUpdateDTO.setId(item);
                        JSONObject data = new JSONObject();
                        data.put(ReturnedPurchaseEnum.OUTSTOCK_ID.getAttr(), "");
                        data.put(ReturnedPurchaseEnum.STATUS.getAttr(), ReturnedPurchaseStatusEnum.WAIT_OUTSTOCK.getStatus());
                        if (returnedPurchaseMap.containsKey(item)) {
                            String returnedStatus = returnedPurchaseMap.get(item);
                            //先要判断退货状态是否已关闭
                            if (!Objects.equals(returnedStatus, ReturnedStatusEnum.CLOSED.getCode())) {
                                if (returnedPurchaseIds.contains(item)) {
                                    data.put(ReturnedPurchaseEnum.RETURNED_STATUS.getAttr(),ReturnedStatusEnum.DELIVERED.getCode());
                                }else {
                                    data.put(ReturnedPurchaseEnum.RETURNED_STATUS.getAttr(),ReturnedStatusEnum.UNRETURNED.getCode());
                                }
                            }
                        }
                        returnedPurchaseUpdateDTO.setData(data);
                        returnedPurchaseList.add(returnedPurchaseUpdateDTO);
                    });
                }
                ReturnedPurchaseUpdateBatchDTO returnedPurchaseUpdateBatchDTO = new ReturnedPurchaseUpdateBatchDTO();
                BeanUtil.copyProperties(outstockDeleteBatchDTO, returnedPurchaseUpdateBatchDTO);
                returnedPurchaseUpdateBatchDTO.setReturnedPurchaseList(returnedPurchaseList);
                returnedPurchaseService.updateBatch(returnedPurchaseUpdateBatchDTO);
            }
            // 盘点出库（重置盘点单关联出库单id）
            if (!inventoryOutstock.isEmpty()) {
                InventoryResetOutstockIdDTO outstockIdDTO = new InventoryResetOutstockIdDTO();
                BeanUtil.copyProperties(outstockDeleteBatchDTO, outstockIdDTO);
                outstockIdDTO.setIdIn(inventoryOutstock);
                outstockIdDTO.setAttr(InventoryEnum.OUTSTOCK_ID.getAttr());
                //一个盘点单下面最多关联一个盘亏出库单，所以删除盘亏出库单时，只要修改盘点单的出库单id字段为0即可。
                inventoryService.resetOutstockIdByIdIn(outstockIdDTO);
            }
            // 调拨出库（重置调拨单关联出库单id）
            if (!transferOutstock.isEmpty()) {
                TransferResetInstockIdDTO resetInstockIdDTO = new TransferResetInstockIdDTO();
                BeanUtil.copyProperties(outstockDeleteBatchDTO, resetInstockIdDTO);
                resetInstockIdDTO.setIdIn(transferOutstock);
                resetInstockIdDTO.setAttr(TransferEnum.OUTSTOCK_ID.getAttr());
                transferService.updateTransferOutstockNum(transferOutstock,corpid,null,false);
                transferService.resetInstockIdByIdIn(resetInstockIdDTO);
            }
            // 生产物料出库（将生产单的关联出库单对应的id删除）
            if (!materielOutstockIdIn.isEmpty()) {
                RetMaterielListDTO retMaterielListDTO = new RetMaterielListDTO();
                BeanUtil.copyProperties(outstockDeleteBatchDTO, retMaterielListDTO);
                retMaterielListDTO.setMaterielOutstockMap(materielOutstockMap);
                retMaterielListDTO.setOutstockIdIn(materielOutstockIdIn);
                retMaterielListDTO.setProductionOrderProductList(outstockProductList);
                // TODO 问题：多次循环内查询
                productionOrderService.updateReturnedMaterielInstock(new InstockProductDeleteBatchVO(),retMaterielListDTO,OutstockTypeEnum.MATERIEL_OUTSTOCK.getStockBusinessType());
            }
            // 更改合同出库状态 和已出库优惠金额、其他费用
            if (!contractOutstockList.isEmpty()) {
                List<OutstockEntityExt> newContractOutstockList = new ArrayList<>(contractOutstockList.size());
                List<OutstockEntityExt> oldContractOutstockList = new ArrayList<>(contractOutstockList.size());
                // 修改合同表数据集合
                List<UpdateDataEntity> updateDataEntityList = new ArrayList<>(contractOutstockList.size());
                List<Long> contractIdList = new ArrayList<>();
                contractOutstockList.forEach(item ->{
                    // 合同ID
                    contractIdList.add( item.getData().getLong(ContractOutstockEnum.REF_ID.getAttr()));
                });
                List<ContractEntityExt> contractEntityExtList = contractModel.findEntitysByIdIn(corpid, 0, contractIdList);
                Map<Long,ContractEntityExt> contractEntityExtMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if(CollectionsUtil.isNotEmpty(contractEntityExtList)){
                    contractEntityExtList.forEach(item ->{
                        contractEntityExtMap.put(item.getId(),item);
                    });
                }
                for (OutstockEntityExt outstockEntityExt : contractOutstockList) {
                    boolean isOldContract = false;
                    for (OutstockProductEntity outstockProductEntity : outstockProductList) {
                        if (Objects.equals(outstockEntityExt.getId(), outstockProductEntity.getOutWarehouseId())) {
                            if (outstockProductEntity.getRefProductId() == null) {
                                // 一个销售出库单下只要有一个ref_product_id值为空,则视为老数据，不做行对应
                                isOldContract = true;
                                break;
                            }
                        }
                    }
                    if (isOldContract) {
                        oldContractOutstockList.add(outstockEntityExt);
                    } else {
                        newContractOutstockList.add(outstockEntityExt);
                    }
                    // 更改合同中已出库优惠金额、其他费用
                    // 销售出库单信息
                    JSONObject outstockEntityExtData = outstockEntityExt.getData();
                    // 合同ID
                    Long contractId = outstockEntityExtData.getLong(ContractOutstockEnum.REF_ID.getAttr());
                    // 根据合同ID和公司ID查询合同信息
                    ContractEntityExt contractEntityExt = contractEntityExtMap.get(contractId);
                    // 合同信息
                    JSONObject contractEntityExtData = contractEntityExt.getData();
                    // 跟新合同中出库优惠金额 = 合同中已出库优惠金额 - 销售出库单中优惠金额
                    String outstockDiscountAmountAttr = ContractEnum.OUTSTOCK_DISCOUNT_AMOUNT.getAttr();
                    String discountAmountAttr = ContractOutstockEnum.DISCOUNT_AMOUNT.getAttr();
                    BigDecimal contractOutstockDiscountAmount = contractEntityExtData.containsKey(outstockDiscountAmountAttr) ? contractEntityExtData.getBigDecimal(outstockDiscountAmountAttr) : new BigDecimal(0);
                    BigDecimal outstockDiscountAmount = outstockEntityExtData.containsKey(discountAmountAttr) ? outstockEntityExtData.getBigDecimal(discountAmountAttr) : new BigDecimal(0);
                    contractEntityExtData.put(ContractEnum.OUTSTOCK_DISCOUNT_AMOUNT.getAttr(), contractOutstockDiscountAmount.subtract(outstockDiscountAmount));
                    // 跟新合同中出库其他费用 = 合同中已出库其他费用 - 销售出库单中其他费用
                    String outstockOtherAttr = ContractEnum.OUTSTOCK_OTHER_EXPENSE.getAttr();
                    String otherExpenseAttr = ContractOutstockEnum.OTHER_EXPENSE.getAttr();
                    BigDecimal contractOutstockOtherExpense = contractEntityExtData.containsKey(outstockOtherAttr) ? contractEntityExtData.getBigDecimal(outstockOtherAttr) : new BigDecimal(0);
                    BigDecimal outstockOtherExpense = outstockEntityExtData.containsKey(otherExpenseAttr) ? outstockEntityExtData.getBigDecimal(otherExpenseAttr) : new BigDecimal(0);
                    contractEntityExtData.put(ContractEnum.OUTSTOCK_OTHER_EXPENSE.getAttr(), contractOutstockOtherExpense.subtract(outstockOtherExpense));
                    updateDataEntityList.add(ExplainUtil.getUpdateData(contractId, contractEntityExtData, corpid));
                }
                // 更新合同数据
                // 下面那个更新合同数据不知道如何整合为一个，望高人改之。
                contractModel.updateBatch(updateDataEntityList, corpid);
                ContractRestoreOutboundDTO contractRestoreOutboundDTO = new ContractRestoreOutboundDTO();
                BeanUtil.copyProperties(outstockDeleteBatchDTO, contractRestoreOutboundDTO);
                contractRestoreOutboundDTO.setNewContractOutstockList(newContractOutstockList);
                contractRestoreOutboundDTO.setOldContractOutstockList(oldContractOutstockList);
                contractRestoreOutboundDTO.setDelOutstockIdList(outstockIdIn);
                contractService.restoreNewContractOutboundAndStatus(contractRestoreOutboundDTO);
                //更新关联产品合同数据待出库状态
                contractProductModel.updateWaitOutStatusById(contractIdList,corpid, WaitOutStockStatusEnum.NORMAL.getCode(),WaitOutStockStatusEnum.NORMAL.getCode());
            }
            // 更新工单状态
            if (!workOrderOutstockList.isEmpty()) {
                WorkOrderRestoreOutboundDTO workOrderRestoreOutboundDTO = new WorkOrderRestoreOutboundDTO();
                BeanUtil.copyProperties(outstockDeleteBatchDTO, workOrderRestoreOutboundDTO);
                workOrderRestoreOutboundDTO.setWorkOrderOutstockList(workOrderOutstockList);
                workOrderRestoreOutboundDTO.setWorkOrderProductList(outstockProductList);
                workOrderRestoreOutboundDTO.setDelOutstockIdList(outstockIdIn);
                workOrderService.restoreOutboundAndStatus(workOrderRestoreOutboundDTO);
            }

            List<Long> childProductIdList = new ArrayList<>();
            childProductIdList.add(-1L);
            Set<Long> warehouseIdList = new HashSet<>();
            for (OutstockProductEntity entity : outstockProductList) {
                if(entity != null && entity.getProductId() != null){
                    childProductIdList.add(entity.getProductId());
                }
                warehouseIdList.add(entity.getWarehouseId());
            }
            try {
                // 更新批次库存 分仓库存 产品库存
                Map<Long, ProductStockUpdateEntity> productAddMap = outstockProductService.delUpdateStock(outstockProductList, corpid, disableBatchProducts);
//                productService.updateProductStockDown(new HashMap<>(16), childProductIdList,productMap,corpid,true, false);
                productService.updateProductStock(productAddMap,corpid);
                List<StockFlowBillUpdateEntity> stockFlowBillUpdateList = new ArrayList<>();
                List<BatchFlowBillUpdateEntity> batchFlowBillUpdateEntityList = new ArrayList<>();
                Map<Long, Long> timeMap = new HashMap<>(outstockList.size());
                outstockList.forEach(item -> {
                    timeMap.put(item.getId(), item.getData().getLong(OutstockEnum.TIME.getAttr()));
                });
                List<Long> batchOutStockIdIn = new ArrayList<>();
                outstockProductList.forEach(item -> {
                    StockFlowBillUpdateEntity stockFlowBillUpdateEntity = new StockFlowBillUpdateEntity(item.getProductId() + "_" + item.getWarehouseId(), item.getProductNum(),Arith.mul(item.getProductNum(), item.getCost()), timeMap.get(item.getOutWarehouseId()), DateTimeUtil.getInt(), item.getOutWarehouseId());
                    stockFlowBillUpdateList.add(stockFlowBillUpdateEntity);
                    if (StringUtil.isNotEmpty(item.getBatch()) && !disableBatchProducts.contains(item.getParentId())) {
                        BatchFlowBillUpdateEntity batchFlowBillUpdateEntity = new BatchFlowBillUpdateEntity(item.getProductId() + "_" + item.getWarehouseId() + "_" + item.getBatch() + "_" + item.getProduceDate() + "_" + item.getGuaranteePeriod(), Arith.sub(0D, item.getProductNum()),Arith.mul(Arith.sub(0D, item.getProductNum()), item.getCost()), timeMap.get(item.getOutWarehouseId()), DateTimeUtil.getInt(), item.getOutWarehouseId());
                        batchFlowBillUpdateEntityList.add(batchFlowBillUpdateEntity);
                        batchOutStockIdIn.add(item.getOutWarehouseId());
                    }
                });
                //发送成本重算信息
                CostRecalculationDTO costRecalculationDTO = new CostRecalculationDTO();
                costRecalculationDTO.setCorpid(corpid);
                costRecalculationDTO.setType(StockTypeEnum.OUT_STOCK.getCode());
                costRecalculationDTO.setMark(BasicConstant.TWO);
                costRecalculationDTO.setOutstockList(outstockList);
                costRecalculationDTO.setStockIdIn(outstockIdIn);
                costRecalculationDTO.setIsWorkFlow(BasicConstant.ONE);
                costRecalculationDTO.setOutstockProductList(outstockProductList);
                costRecalculationDTO.setBatchOutStockIdIn(batchOutStockIdIn);
                costRecalculationDTO.setStockFlowBillUpdateList(stockFlowBillUpdateList);
                costRecalculationDTO.setBatchFlowBillUpdateEntityList(batchFlowBillUpdateEntityList);
                /*stockFlowBillService.caculateStockModification4Delete(outstockIdIn, stockFlowBillUpdateList, XbbRefTypeEnum.OUTSTOCK.getCode(), corpid);
                batchFlowBillService.batchFlowModification4Delete(batchOutStockIdIn, batchFlowBillUpdateEntityList, XbbRefTypeEnum.OUTSTOCK.getCode(), corpid);*/
                oriStockService.reSetWarehouseOriStock(corpid,warehouseIdList);
                costRecalculationProducer.sendMessage(costRecalculationDTO);
                // 删除销售出库单时 更新以销定购表 以及智能补货表数据
                if (Objects.equals(XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode(),businessType)){
                    Map<String,Double> balanceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    List<String> onlyKeyList = new ArrayList<>();
                    // key=productId  value=删除的产品总量
                    Map<Long,Double> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    List<Long> productIdList = new ArrayList<>();
                    List<Long> contractProductIdList = new ArrayList<>();
                    Set<Long> contractIdSet = new HashSet<>();
                    for (OutstockProductEntity outstockProductEntity : outstockProductList) {
                        Long productId = outstockProductEntity.getProductId();
                        Double productNum = outstockProductEntity.getProductNum();
                        if (productMap.containsKey(productId)){
                            productMap.put(productId,Arith.add(productMap.get(productId),productNum));
                        }else {
                            productMap.put(productId,productNum);
                            productIdList.add(productId);
                        }
                        contractProductIdList.add(outstockProductEntity.getRefProductId());
                        contractIdSet.add(outstockProductEntity.getRefId());
                        // 封装删除的同一个合同下的某一个产品总量
                        String onlyKey = outstockProductEntity.getRefProductId() + "_" + outstockProductEntity.getProductId();
                        if(!balanceMap.containsKey(onlyKey)){
                            onlyKeyList.add(onlyKey);
                            balanceMap.put(onlyKey,outstockProductEntity.getProductNum());
                        }else {
                            balanceMap.put(onlyKey,Arith.add(balanceMap.get(onlyKey),outstockProductEntity.getProductNum()));
                        }
                    }
                    // 根据onlyKeyList查询出所有结存数据
                    List<PurchaseBalanceEntity> purchaseBalanceEntityList = purchaseBalanceModel.findByOnlyKeys(corpid, onlyKeyList);
                    // 封装结存的超发库存以及结存方案已与产品确认 先回退超发的 多余的再回退到结余
                    if(CollectionsUtil.isNotEmpty(purchaseBalanceEntityList)){
                        for (PurchaseBalanceEntity purchaseBalanceEntity : purchaseBalanceEntityList) {
                            String onlyKey = purchaseBalanceEntity.getOnlyKey();
                            if (balanceMap.containsKey(onlyKey)){
                                Double balanceNum = purchaseBalanceEntity.getBalanceNum();
                                Double exceedStockNum = purchaseBalanceEntity.getExceedStockNum();
                                Double delProductNum = balanceMap.get(onlyKey);
                                // 删除数量 如果大于超发的 则超发库存全部回退 多余的回到结存 小于的话全部回退到超发库存
                                purchaseBalanceEntity.setExceedStockNum(delProductNum >= exceedStockNum ? 0D : Arith.sub(exceedStockNum,delProductNum));
                                // 删除的数量如果大于超发 则结存数量为之前的加上删除的大于超发的那部分  如果小于超发 则全部回退到超发 结存不变
                                purchaseBalanceEntity.setBalanceNum(delProductNum >= exceedStockNum ? Arith.add(purchaseBalanceEntity.getBalanceNum(),Arith.sub(delProductNum,exceedStockNum)): purchaseBalanceEntity.getBalanceNum());
                            }
                        }
                        try {
                            purchaseBalanceModel.updateBatch(purchaseBalanceEntityList,corpid);
                        }catch (Exception e){
                            LOG.error("OutstockServiceImpl.deleteBatch() 更新采购结存表数据时出错", e);
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                        }
                    }
                    // 查询出删除的销售出库单关联的所有产品的智能补货数据
                    List<SmartReplenishmentEntity> smartReplenishmentEntityList = smartReplenishmentModel.getByProductList(corpid,productIdList);
                    if (CollectionsUtil.isNotEmpty(smartReplenishmentEntityList)){
                        for (SmartReplenishmentEntity smartReplenishmentEntity : smartReplenishmentEntityList) {
                            Long smartProductId = smartReplenishmentEntity.getProductId();
                            if (productMap.containsKey(smartProductId)){
                                smartReplenishmentEntity.setWaitOutstockNum(Arith.add(smartReplenishmentEntity.getWaitOutstockNum(),productMap.get(smartProductId)));
                            }
                        }
                        try {
                            smartReplenishmentModel.updateBatch(smartReplenishmentEntityList,corpid);
                        }catch (Exception e){
                            LOG.error("OutstockServiceImpl.deleteBatch() 更新智能补货表数据时出错", e);
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                        }
                    }
                    // 处理合同产品表中缺货数量
                    if (CollectionsUtil.isNotEmpty(contractProductIdList)){
                        List<ContractProductEntity> contractProductEntityList = contractProductModel.getById(contractProductIdList, corpid);
                        if (CollectionsUtil.isNotEmpty(contractProductEntityList)){
                            contractHelp.handleWaitPurchaseNum(corpid,contractProductEntityList,contractIdSet);
                            try {
                                contractProductModel.updateBatch(contractProductEntityList,corpid);
                            }catch (Exception e){
                                LOG.error("OutstockServiceImpl.deleteBatch() 更新合同产品表中缺货数量数据时出错", e);
                                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                            }
                        }

                    }
                }
            } catch (XbbException e) {
                LOG.error("生成出库单产品出错",e);
            }
            final Integer outstockType = type;
            if (Objects.isNull(outstockType)){
                LOG.error("outstockDelErr:" + JSONObject.toJSONString(outstockDeleteBatchDTO));
                LOG.error("outstockDelErrLen:" + outstockList.size());
            }

            List<OutstockProductEntity> finalOutstockProductList = outstockProductList;
            Runnable runnable = () -> {
                try {
                    //查询编号
                    Map<Long, String> outstockIdAndno = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    for (OutstockEntityExt entityExt : outstockList) {
                        Long outstockId = entityExt.getId();
                        String sheetNo = entityExt.getSerialNo();
                        outstockIdAndno.put(outstockId, sheetNo);
                    }

                    //产品分仓库存数据
                    BoolQueryBuilder boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                    boolQueryBuilder.filter(termsQuery(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.PRODUCT_ID), childProductIdList));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termQuery(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.WAREHOUSE_CHECKED), 1));
                    List<String> productWarehouseFieldList = new ArrayList<>();
                    productWarehouseFieldList.add(ProductWarehouseSubFormEnum.getAttrConnectData(ProductWarehouseSubFormEnum.PRODUCT_ID));
                    productWarehouseFieldList.add(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.WAREHOUSE_ID));
                    productWarehouseFieldList.add(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.WAREHOUSE_NAME));
                    productWarehouseFieldList.add(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.NUM));
                    // 这次查询主要是为了用于日志信息记录，考虑线程处理不影响主业务
                    List<PaasFormDataEntity> childProductList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE, boolQueryBuilder, PaasFormDataEntity.class, productWarehouseFieldList);
                    List<ProductWarehouseEntity> productWarehouseEntities = transferSubFormHelper.transferFormDataToProductWarehouseList(childProductList);

                    Map<String, ProductWarehouseEntity> outstockProductStockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    productWarehouseEntities.forEach(entityExt -> {
                        String key = entityExt.getProductId() + "_" + entityExt.getWarehouseId();
                        outstockProductStockMap.put(key, entityExt);
                    });

                    // 出库单一对多产品
                    Map<Long, List<OutstockProductEntity>> outstockIdAndListMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    ListIterator<OutstockProductEntity> listIterator = finalOutstockProductList.listIterator();
                    while (listIterator.hasNext()) {
                        OutstockProductEntity outstockProduct = listIterator.next();
                        Long outstockId = outstockProduct.getOutWarehouseId();
                        List<OutstockProductEntity> outstockProductEntityList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        outstockProductEntityList.add(outstockProduct);

                        if (outstockIdAndListMap.get(outstockId) == null) {
                            outstockIdAndListMap.put(outstockId, outstockProductEntityList);
                        } else {
                            outstockProductEntityList.addAll(outstockIdAndListMap.get(outstockId));
                            outstockIdAndListMap.put(outstockId, outstockProductEntityList);
                        }
                    }
                    // 各个出库单对应的出库产品
                    Map<Long, List<String>> outstockListMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    Iterator<Map.Entry<Long, List<OutstockProductEntity>>> outIterator = outstockIdAndListMap.entrySet().iterator();
                    while (outIterator.hasNext()) {
                        Map.Entry<Long, List<OutstockProductEntity>> entry = outIterator.next();
                        Long outstockId = entry.getKey();
                        List<OutstockProductEntity> outstockProductEntities = entry.getValue();
                        List<Long> wareIdList = new ArrayList<>();
                        if(CollectionsUtil.isNotEmpty(outstockProductEntities)){
                            outstockProductEntities.forEach(item -> wareIdList.add(item.getWarehouseId()));
                        }
                        Map<Long,String> warehouseNameMap  = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        if (CollectionsUtil.isNotEmpty(wareIdList)){
                            Map<String,Object> params = new HashMap<>();
                            params.put("corpid", corpid);
                            params.put("del",0);
                            params.put("idIn",wareIdList);
                            List<WarehouseEntityExt> warehouseModelEntitys = warehouseModel.findEntitys(params);
                            if (CollectionsUtil.isNotEmpty(warehouseModelEntitys)){
                                for (WarehouseEntityExt warehouseModelEntity : warehouseModelEntitys) {
                                    Long id = warehouseModelEntity.getId();
                                    JSONObject data = warehouseModelEntity.getData();
                                    String warehouseName = "";
                                    if (Objects.nonNull(data)){
                                        warehouseName = FastJsonHelper.getStringOrDefaultFromFormData(data, WarehouseEnum.WAREHOUSE_NAME.getAttr(), "");
                                    }
                                    warehouseNameMap.put(id,warehouseName);
                                }
                            }
                        }
                        List<String> outProductStrList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        for (OutstockProductEntity outstockProduct : outstockProductEntities) {
                            Double productNum = outstockProduct.getProductNum() == null ? 0D : outstockProduct.getProductNum();
                            Double cost = outstockProduct.getCost() == null ? 0D : outstockProduct.getCost();

                            String key = outstockProduct.getProductId() + "_" + outstockProduct.getWarehouseId();
                            ProductWarehouseEntity productWarehouseEntity = outstockProductStockMap.get(key);
                            // 拼接产品信息
                            String productName = outstockProduct.getProductName() == null ? "--" : outstockProduct.getProductName();
                            String productNo = outstockProduct.getProductNo() == null ? "--" : outstockProduct.getProductNo();
                            String productSpecification = Objects.equals(outstockProduct.getProductSpecification(), "") ? "--" : outstockProduct.getProductSpecification();
                            productSpecification = productSpecification.replaceAll("[`~!@#$%^&*\",.，。【】“”'‘’()+=|{}'.;'\\[\\]<>/?~@#￥%……&*]|\\s*|\t|\r|\n", "");
                            if (productSpecification.contains(":")) {
                                productSpecification = productSpecification.replace(":", "/");
                            }
//                            String warehouseName = productWarehouseEntity == null ? "--" : productWarehouseEntity.getWarehouseName();
                            String warehouseName = warehouseNameMap.get(outstockProduct.getWarehouseId()) == null ? "--" :warehouseNameMap.get(outstockProduct.getWarehouseId());
                            String batch = Objects.equals(outstockProduct.getBatch(), "") ? "--" : outstockProduct.getBatch();
                            StringBuilder sb = new StringBuilder();
                            sb.append("产品名称：").append(productName).append("，").append("产品编号：").append(productNo).append("，")
                                    .append("规格：").append(productSpecification).append("，").append("仓库：").append(warehouseName).append("，")
                                    .append("出库数量：").append(productNum).append("，").append("成本：").append(cost).append("，")
                                    .append("批次号：").append(batch).append("；<br/>");
                            outProductStrList.add(sb.toString());
                        }
                        outstockListMap.put(outstockId, outProductStrList);
                    }

                    //生成删除日志(区分单个删除和批量删除)
                    String userId = outstockDeleteBatchDTO.getUserId();
                    String userName = outstockDeleteBatchDTO.getLoginUserName();
                    List<String> list = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 出入库单流水号不能为空
                    Iterator<Map.Entry<Long, String>> iterator = outstockIdAndno.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<Long, String> entry = iterator.next();
                        Long key = entry.getKey();
                        String value = outstockIdAndno.get(key);
                        if (outstockListMap.containsKey(key)) {
                            List<String> outstockProductStrList = outstockListMap.get(key);
                            String outstockProductStr = StringUtils.join(outstockProductStrList, "，");
                            StringBuilder sb = new StringBuilder();
                            sb.append(value).append("<br/>").append("（").append(outstockProductStr).append("）");
                            list.add(sb.toString());
                        } else {
                            list.add(value);
                        }
                    }
                    OperateTypeEnum operateTypeEnum = OperateTypeEnum.DELETE;
                    if (Objects.equals(1, outstockDeleteBatchDTO.getIsBusinessRule())) {
                        operateTypeEnum = OperateTypeEnum.RULE_DELETE;
                    }
                    OutstockTypeEnum outstockTypeEnum = OutstockTypeEnum.getByCode(outstockType);
                    String nameStr = StringUtils.join(list, "，<br/>");
                    if (outstockIdIn.size() > 1) {
                        String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_BATCH_DELETE_FORM_DETAIL), userName, XbbRefTypeEnum.getByCode(outstockTypeEnum.getStockBusinessType()).getName(), outstockIdIn.size());
                        List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        InfoArrPojo infoArrPojo = new InfoArrPojo();
                        infoArrPojo.setTitle(OutstockEnum.SHEET_NO.getAttrName());
                        infoArrPojo.setContent(nameStr);
                        infoArrPojoList.add(infoArrPojo);
                        mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, userName, outstockTypeEnum.getOperateModuleTypeEnum(), operateTypeEnum,
                                "", "", memo, outstockDeleteBatchDTO.getHttpHeader());
                    } else if (Objects.equals(outstockIdIn.size(), 1)) {
                        Long outstockLogId = outstockIdIn.get(0);
                        String outstockLogNo = outstockIdAndno.get(outstockLogId);
                        String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_DELETE_WORK), userName, XbbRefTypeEnum.getByCode(outstockTypeEnum.getStockBusinessType()).getName(), outstockLogNo);
                        List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        InfoArrPojo infoArrPojo = new InfoArrPojo();
                        infoArrPojo.setTitle(OutstockEnum.PRODUCT.getAttrName());
                        infoArrPojo.setContent(nameStr);
                        infoArrPojoList.add(infoArrPojo);
                        mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, userName, outstockTypeEnum.getOperateModuleTypeEnum(), operateTypeEnum,
                                outstockLogId.toString(), outstockLogNo, memo, outstockDeleteBatchDTO.getHttpHeader());
                    }
                } catch (Exception e) {
                    LOG.error("outstockServiceImpl.deleteBatch 记录日志执行出错：", e);
                }
            };
            threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
        } catch (XbbException e){
            removeDelLack(outstockDeleteBatchDTO.getDataIdList(),corpid);
            if (isRollBack) {
                boolean isCheck = concurrentLockAspect.checkStock(corpid);
                if (isCheck){
                    // 没开启负库存的才需要回滚
                    concurrentLockAspect.deleteOutstockStockRollBack(outstockProductList);
                }
            }
            throw e;
        } catch (Exception e) {
            removeDelLack(outstockDeleteBatchDTO.getDataIdList(),corpid);
            if (isRollBack) {
                boolean isCheck = concurrentLockAspect.checkStock(corpid);
                if (isCheck){
                    // 没开启负库存的才需要回滚
                    concurrentLockAspect.deleteOutstockStockRollBack(outstockProductList);
                }
            }
            LOG.error("outstockServiceImpl.deleteBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
//        removeDelLack(outstockDeleteBatchDTO.getDataIdList(),corpid);
//        lackMsg(lackIdList,corpid);
        return outstockDeleteBatchVO;
    }

    /**
     * 产品或仓库删除的出库记录不做校验
     * @param outstockList
     * @param outstockIdIn
     * @param corpid
     * @throws XbbException
     */
    public void warehouseBoundCheck(List<OutstockEntityExt> outstockList, List<Long> outstockIdIn, String corpid) throws XbbException {
        Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put(StringConstant.CORPID,corpid);
        param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
        param.put("outWarehouseIdIn",outstockIdIn);
        param.put("orderByStr","product_id,warehouse_id");
        param.put("productDel",0);
        param.put("warehouseDel",0);
        param.put("columns","out_warehouse_id,product_id,warehouse_id,product_name");
        List<OutstockProductEntity> outstockProductEntityList = outstockProductModel.findEntitys(param);
        Set<String> warehouseKeyList = new HashSet<>();
        Map<String,OutstockProductEntity> warehouseKeyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        outstockProductEntityList.forEach(item -> {
            warehouseKeyList.add(item.getProductId() + "_" + item.getWarehouseId());
            warehouseKeyMap.put(item.getProductId() + "_" + item.getWarehouseId(),item);
        });
        //出库只查询绑定的分仓
        List<String> existWarehouseKeyList = productWarehouseModel.getExistWarehouseKeyList(corpid, warehouseKeyMap.keySet(),1);
        warehouseKeyList.removeAll(existWarehouseKeyList);
        if (!warehouseKeyList.isEmpty()) {
            for (String warehouseKey : warehouseKeyList) {
                for (OutstockEntityExt outstockEntityExt : outstockList) {
                    OutstockProductEntity entity = warehouseKeyMap.get(warehouseKey);
                    if (Objects.isNull(entity)) {
                        continue;
                    }
                    if (Objects.equals(outstockEntityExt.getId(),entity.getOutWarehouseId())) {
                        Long warehouseId = entity.getWarehouseId();
                        String productName = entity.getProductName();
                        WarehouseEntityExt warehouseEntityExt = warehouseModel.getByKey(warehouseId,corpid);
                        throw new XbbException(ProductErrorCodeEnum.API_ERROR_205067,String.format(ProductErrorCodeEnum.API_ERROR_205067.getMsg(),outstockEntityExt.getSerialNo(),productName,warehouseEntityExt.getData().getString(WarehouseEnum.WAREHOUSE_NAME.getAttr())));

                    }
                }
            }
        }
    }

    public void removeDelLack(List<Long> outstockIdList, String corpid) {
        for (Long outstockId : outstockIdList) {
            String key = corpid + "_" + outstockId;
            paasRedisHelper.removeValue(RedisPrefixConstant.OUTSTOCK_DEL,key);
        }
    }

    public void lackMsg(List<Long> lackIdList, String corpid) throws XbbException {
        if (!lackIdList.isEmpty()){
            Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            map.put(StringConstant.CORPID,corpid);
            map.put("idIn",lackIdList);
            map.put("columns","serial_no");
            List<OutstockEntityExt> outstockEntityExtList = outstockModel.findEntitys(map);
            StringBuilder stringBuilder = new StringBuilder();
            outstockEntityExtList.forEach(item -> stringBuilder.append(item.getSerialNo()).append(","));
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404, ErrorMessageConstant.DATA_DEL_LACK_ERROR_MSG,stringBuilder.toString());
        }
    }

    public List<Long> checkRedisKey(String corpid, List<Long> outstockList) {
        Iterator<Long> iterator = outstockList.iterator();
        List<Long> lackIdList = new ArrayList<>();
        while (iterator.hasNext()){
            Long outstockId = iterator.next();
            String key = corpid + "_" + outstockId;
            Long value = paasRedisHelper.getIncrNum(RedisPrefixConstant.OUTSTOCK_DEL,key, TimeConstant.SECONDS_PER_MINUTE,1,1);
            if (value > 1L){ lackIdList.add(outstockId);
                lackIdList.add(outstockId);
                iterator.remove();
            }
        }
        return lackIdList;
    }

    private Set<Long> checkOutstockDelete(String corpid, List<OutstockEntityExt> outstockList, Integer businessType) throws XbbException {
        List<Long> materialOutstockIdList = new ArrayList<>();
        List<Long> contractOutstockIdList = new ArrayList<>();
        List<Long> assembleIdList = new ArrayList<>();
        List<Long> transferIdList = new ArrayList<>();
        Set<Long> outstockIdList = new HashSet<>();
        Set<String> outstockSerialNo = new HashSet<>();
        Map<Long,String> serialNoMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,String> transferSerialNoMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, String> outstockToSerialNo = new HashMap<>();
        for (OutstockEntityExt item : outstockList) {
            outstockIdList.add(item.getId());
            outstockToSerialNo.put(item.getId(), item.getSerialNo());
            JSONObject jsonObject = item.getData();
            Integer type = jsonObject.getInteger(OutstockEnum.TYPE.getAttr());
            Long refId = jsonObject.getLong(OutstockEnum.REF_ID.getAttr());
            if (Objects.isNull(refId)) {
                continue;
            }
            if (Objects.equals(type, OutstockTypeEnum.MATERIEL_OUTSTOCK.getCode())) {
                materialOutstockIdList.add(item.getId());
            } else if (Objects.equals(type, OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
                contractOutstockIdList.add(item.getId());
            } else if (Objects.equals(type, OutstockTypeEnum.ASSEMBLE_OUTSTOCK.getCode())) {
                assembleIdList.add(refId);
            } else if (Objects.equals(type, OutstockTypeEnum.TRANSFER_OUTSTOCK.getCode())) {
                transferIdList.add(refId);
            }
            if (Objects.equals(type, OutstockTypeEnum.TRANSFER_OUTSTOCK.getCode())) {
                transferSerialNoMap.put(refId,item.getSerialNo());
            } else {
                serialNoMap.put(item.getId(),item.getSerialNo());
            }
        }
        //销售出库单删除校验关联的合同是否有正在审批中的退货退款单
        if (Objects.equals(XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode(), businessType)) {
            List<String> refundContractIdList;
            List<String> contractIdList = outstockList.stream().map(item -> item.getData().getString(ContractOutstockEnum.REF_ID.getAttr())).collect(Collectors.toList());
            if (!commonHelp.isOpenWorkFlow(corpid)) {
                Map<String, Object> processParam = new HashMap<>(8);
                processParam.put(StringConstant.COLUMNS, "data");
                processParam.put(StringConstant.CORPID, corpid);
                processParam.put(StringConstant.BUSINESS_TYPE, XbbRefTypeEnum.REFUND.getCode());
                processParam.put("flowStatusIn", Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType()));
                processParam.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
                processParam.put("dataContractIdIn", contractIdList);
                List<PaasProcessDataEntity> paasProcessDataList = paasProcessDataModel.list(processParam);
                refundContractIdList = paasProcessDataList.stream().map(item -> JSONObject.parseObject(item.getData()).getString(RefundBaseEnum.CONTRACT_ID.getAttr())).collect(Collectors.toList());
            } else {
                Map<String, Object> refundParam = new HashMap<>(8);
                refundParam.put(StringConstant.COLUMNS, "data");
                refundParam.put(StringConstant.CORPID, corpid);
                refundParam.put("dataContractIdIn", contractIdList);
                refundParam.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
                refundParam.put("flowStatusIn", Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType()));
                List<RefundEntityExt> refundList = refundModel.findEntitys(refundParam);
                refundContractIdList = refundList.stream().map(item -> item.getData().getString(RefundBaseEnum.CONTRACT_ID.getAttr())).collect(Collectors.toList());
            }
            if (refundContractIdList.size() > 0) {
                for (OutstockEntityExt outstockEntityExt : outstockList) {
                    if (refundContractIdList.contains(outstockEntityExt.getData().getString(ContractOutstockEnum.REF_ID.getAttr()))) {
                       throw new XbbException(ErrorCodeEnum.API_ERROR_212029, ErrorCodeEnum.API_ERROR_212029.getMsg(), outstockEntityExt.getSerialNo());
                    }
                }
            }
        }
        //现在删除时全都需要查询产品批次保质期序列号状态
        Map<String,Object> outstockProductParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        outstockProductParam.put("outstockIdIn", outstockIdList);
        outstockProductParam.put("corpid", corpid);
        outstockProductParam.put("del", 0);
        List<OutstockProductEntity> outstockProductEntityList = outstockProductModel.findEntitys(outstockProductParam);
        //批次序列号校验
        Set<Long> disableBatchProducts = saasDeleteHelp.checkDocumentDelete(corpid, outstockProductEntityList, null, outstockToSerialNo);

        productSerialService.preCheckDelSerial(new ArrayList<>(outstockIdList), corpid, businessType);

        //需要重置一次outstockIdList给下面的业务用
        outstockIdList = new HashSet<>();
        if (!materialOutstockIdList.isEmpty()) {
            // 查询【生产领料出库单】是否存在下游单据【生产退料入库单】
            for (OutstockProductEntity outstockProductEntity : outstockProductEntityList) {
                if (!materialOutstockIdList.contains(outstockProductEntity.getOutWarehouseId())) {
                    continue;
                }
                if (Objects.nonNull(outstockProductEntity.getInstockNum()) && outstockProductEntity.getInstockNum() > BasicConstant.ZERO) {
                    outstockIdList.add(outstockProductEntity.getOutWarehouseId());
                }
            }
            if (outstockIdList.size() > 0) {
                for (Long outstockId : outstockIdList) {
                    outstockSerialNo.add(serialNoMap.get(outstockId));
                }
                for (OutstockEntityExt outstockEntityExt : outstockList) {
                    if (outstockIdList.contains(outstockEntityExt.getId())) {
                        outstockSerialNo.add(outstockEntityExt.getSerialNo());
                    }
                }
                if (outstockSerialNo.size() > 0) {
                    throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212028, String.format(OutstockErrorCodeEnum.API_ERROR_212028.getMsg(), outstockSerialNo.toString()));
                }
            }
        }
        if (!contractOutstockIdList.isEmpty()) {
            for (OutstockProductEntity outstockProductEntity : outstockProductEntityList) {
                if (!contractOutstockIdList.contains(outstockProductEntity.getOutWarehouseId())) {
                    continue;
                }
                if (Objects.nonNull(outstockProductEntity.getInstockNum()) && outstockProductEntity.getInstockNum() > BasicConstant.ZERO) {
                    outstockIdList.add(outstockProductEntity.getOutWarehouseId());
                }
            }
            if (outstockIdList.size() > 0) {
                for (Long outstockId : outstockIdList) {
                    outstockSerialNo.add(serialNoMap.get(outstockId));
                }
                for (OutstockEntityExt outstockEntityExt : outstockList) {
                    if (outstockIdList.contains(outstockEntityExt.getId())) {
                        outstockSerialNo.add(outstockEntityExt.getSerialNo());
                    }
                }
                if (outstockSerialNo.size() > 0) {
                    throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212029, String.format(OutstockErrorCodeEnum.API_ERROR_212029.getMsg(), outstockSerialNo.toString()));
                }
            }
        }
        if (!assembleIdList.isEmpty()) {
            //装配出库单不可以单独删除，要去删除装配单的时候需要一并删除出入库单
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
            boolQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(), assembleIdList));
            // 设置join_field
            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_ASSEMBLE.getType()));
            searchSourceBuilder.query(boolQueryBuilder);
            List<PaasFormDataEntityExt> entityExts = paasEsModel.list(searchSourceBuilder, IndexTypeEnum.IDX_SAAS_ASSEMBLE, null, null, null);
            if (Objects.nonNull(entityExts) && entityExts.size() > 0) {
                throw new XbbException(AssembleErrorCodeEnum.API_ERROR_231019, AssembleErrorCodeEnum.API_ERROR_231019.getMsg());
            }
        }
        if (!transferIdList.isEmpty()) {
            BoolQueryBuilder builder = boolQuery();
            builder.filter(termQuery("corpid.keyword", corpid));
            builder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
            builder.filter(termsQuery(InstockEnum.getEsAttr4Keyword(InstockEnum.REF_ID), transferIdList));
            builder.filter(termQuery(InstockEnum.getEsAttr4Keyword(InstockEnum.TYPE), InstockTypeEnum.TRANSFER_INSTOCK.getCode()));
            builder.filter(termsQuery("flowStatus", FlowStatusEnum.normalStatus()));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(InstockEnum.getAttrConnectData(InstockEnum.REF_ID));
            List<PaasFormDataEntityExt> entityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INSTOCK, builder, PaasFormDataEntityExt.class, fieldList);
            List<Long> refIdList = new ArrayList<>();
            for (PaasFormDataEntityExt entityExt : entityExtList) {
                refIdList.add(entityExt.getData().getLong(InstockEnum.REF_ID.getAttr()));
            }
            if (!refIdList.isEmpty()){
                for (Long redId : refIdList) {
                    outstockSerialNo.add(transferSerialNoMap.get(redId));
                }
                throw new XbbException(TransferErrorCodeEnum.API_ERROR_229018, String.format(TransferErrorCodeEnum.API_ERROR_229018.getMsg(),outstockSerialNo));
            }
        }
        return disableBatchProducts;
    }

    /**
     * 更新采购退货产品的出库数量
     *
     * @param returnedPurchaseIds 采购退货单
     * @param corpid 公司id
     * @param delOutstockIdList 当前已经被删除的出库单id
     * @throws XbbException 异常
     */
    public Set<Long> updateReturnedPurchaseProductOutNumBatch(Set<Long> returnedPurchaseIds, String corpid,List<Long> delOutstockIdList) throws XbbException {
        //存放已经没有下游出库单的采购退货单ID
        Set<Long> returnedStatusSet = new HashSet<>();
        if(returnedPurchaseIds.isEmpty()||corpid.isEmpty()){
            return returnedStatusSet;
        }
        BoolQueryBuilder outstockQueryBuilder = boolQuery();
        outstockQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        outstockQueryBuilder.filter(termQuery(OutstockEnum.getEsAttr4Keyword(OutstockEnum.TYPE), OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode()));
        outstockQueryBuilder.filter(termsQuery(OutstockEnum.getEsAttr4Keyword(OutstockEnum.REF_ID), new ArrayList<>(returnedPurchaseIds)));
        outstockQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        outstockQueryBuilder.mustNot(termsQuery(FieldTypeEnum.DATAID.getAlias(), delOutstockIdList));
        List<PaasFormDataEntityExt> outstockList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OUTSTOCK, outstockQueryBuilder, PaasFormDataEntityExt.class, Collections.singletonList(FieldTypeEnum.DATAID.getAlias()));

        List<Long> outstockIds = new ArrayList<>();
        for (PaasFormDataEntityExt entityExt : outstockList) {
            outstockIds.add(entityExt.getDataId());
        }
        //获取采购退货出库单产品
        Map<String, Object> param = new HashMap<>(16);
        param.put("corpid", corpid);
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("outstockIdIn", outstockIds);
        List<OutstockProductEntity> outstockProductEntities = outstockProductModel.findEntitys(param);

        Map<Long, Double> refProductIdNum = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for(OutstockProductEntity outstockProductEntity : outstockProductEntities){
            Long key = outstockProductEntity.getData().getLong(BusinessConstant.REF_PRODUCT_ID);
            Double num = refProductIdNum.get(key)==null ? outstockProductEntity.getProductNum() : Arith.add(outstockProductEntity.getProductNum(), refProductIdNum.get(key));
            refProductIdNum.put(key,num);
        }
        List<ReturnedPurchaseProductEntity> returnedPurchaseProducts = returnedPurchaseProductModel.getReturnedPurchaseProductByReturnedPurchaseIdIn(corpid, new ArrayList<>(returnedPurchaseIds));
        for(ReturnedPurchaseProductEntity returnedPurchaseProductEntity : returnedPurchaseProducts){
            if(refProductIdNum.containsKey(returnedPurchaseProductEntity.getId())){
                returnedPurchaseProductEntity.setOutstockNum(refProductIdNum.get(returnedPurchaseProductEntity.getId()));
            }else{
                //下游数据已删除完
                returnedPurchaseProductEntity.setOutstockNum(0D);
                //下游数据删除完，代表该采购退货单未入库
                Long returnPurchaseId = returnedPurchaseProductEntity.getReturnPurchaseId();
                returnedStatusSet.add(returnPurchaseId);
            }
            returnedPurchaseProductEntity.setUpdateTime(DateTimeUtil.getInt());
        }
        returnedPurchaseProductModel.updateBatch(returnedPurchaseProducts,corpid);
        return returnedStatusSet;

    }

    @Override
    public void batchEditAttr(OutstockEditAttrUpdateDTO outstockEditAttrUpdateDTO) throws XbbException {
        try {
            List<OutstockUpdateDTO> transferList = new ArrayList<>();
            outstockEditAttrUpdateDTO.getDataIdList().forEach((item)->{
                OutstockUpdateDTO outstockUpdateDTO = new OutstockUpdateDTO();
                outstockUpdateDTO.setId(item);
                JSONObject data = ProSaveHelp.getBatchUpdateData(outstockEditAttrUpdateDTO.getFieldEditedList());
                outstockUpdateDTO.setData(data);
                transferList.add(outstockUpdateDTO);
            });
            List<OutstockEntityExt> outstockEntityList  = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (!transferList.isEmpty()) {
                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put("corpid", outstockEditAttrUpdateDTO.getCorpid());
                param.put("idIn", outstockEditAttrUpdateDTO.getDataIdList());
                outstockEntityList = outstockModel.findEntitys(param);
                if (Objects.isNull(outstockEntityList)){
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                }
                OutstockUpdateBatchDTO outstockUpdateBatchDTO = new OutstockUpdateBatchDTO();
                BeanUtil.copyProperties(outstockEditAttrUpdateDTO, outstockUpdateBatchDTO);
                outstockUpdateBatchDTO.setOutstockList(transferList);
                updateBatch(outstockUpdateBatchDTO);
            }

            // 批量编辑日志
            List<String> updataItemList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> dataIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (OutstockEntityExt item : outstockEntityList) {
                dataIdList.add(item.getId());
                String serialNo = item.getSerialNo();
                updataItemList.add(serialNo);
            }
            String updataItem = StringUtils.join(updataItemList, "，");
            String userId = outstockEditAttrUpdateDTO.getUserId();
            String corpid = outstockEditAttrUpdateDTO.getCorpid();
            String loginUserName = outstockEditAttrUpdateDTO.getLoginUserName();
            // 标签特殊处理
            Integer fieldType = outstockEditAttrUpdateDTO.getFieldType();
            logHelp.analysisLabel(corpid, fieldType, outstockEditAttrUpdateDTO.getIsFieldDependence(), outstockEditAttrUpdateDTO.getLogFieldEditedList());

            String changedLogItemsStr = logHandleHelp.getChangedLogItemsStr(outstockEditAttrUpdateDTO.getLogFieldEditedList());
            if(dataIdList.size() > 1 ){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_FORM_DATA_BATCH_ATTR), loginUserName, XbbRefTypeEnum.OUTSTOCK.getName(),
                        changedLogItemsStr, dataIdList.size());
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(XbbRefTypeEnum.OUTSTOCK.getName());
                infoArrPojo.setContent(updataItem);
                infoArrPojoList.add(infoArrPojo);
                mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, loginUserName, OperateModuleTypeEnum.OUTSTOCK, OperateTypeEnum.EDIT,
                        "", "", memo, outstockEditAttrUpdateDTO.getHttpHeader());
            } else if (Objects.equals(dataIdList.size(), 1)){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_FORM_DATA_ATTR), loginUserName, XbbRefTypeEnum.OUTSTOCK.getName(), updataItem,
                        changedLogItemsStr);
                mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.OUTSTOCK, OperateTypeEnum.EDIT,
                        dataIdList.get(0).toString(), updataItem, memo, outstockEditAttrUpdateDTO.getHttpHeader());
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("outstockService.batchEditAttr 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public void formatLinkAddExplain(HandlerExplainInLinkItemDTO handlerExplainInLinkItemDTO) throws XbbException {
        Long linkDataId = handlerExplainInLinkItemDTO.getLinkDataId();
        PaasFormDataEntityExt paasFormDataEntityExt = handlerExplainInLinkItemDTO.getPaasFormDataEntityExt();
        JSONObject dataList = paasFormDataEntityExt.getData();
        String serialNo = paasFormDataEntityExt.getSerialNo();
        String corpid = handlerExplainInLinkItemDTO.getCorpid();
        handlerExplainInLinkItemDTO.setBusinessType(handlerExplainInLinkItemDTO.getPaasFormExplainEntity().getBusinessType());
        CustomerEntityExt customerEntityExt = null;
        FieldAttrEntity fieldAttr = null;
        if (Objects.equals(handlerExplainInLinkItemDTO.getLinkBusinessType(),XbbRefTypeEnum.CONTRACT.getCode())){
            Long customerId = dataList.getJSONArray(ContractEnum.LINK_CUSTOMER.getAttr()).getJSONObject(0).getLong(BusinessConstant.ID);
            customerEntityExt = customerModel.getByKey(customerId,corpid);
            // 判断客户电话子表单是否启用
            if(Objects.nonNull(customerEntityExt)){
                PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(customerEntityExt.getFormId(),corpid);
                if(Objects.nonNull(paasFormExplainEntity) && Objects.equals(paasFormExplainEntity.getDel(), DelEnum.NORMAL.getDel())) {
                    String explains = paasFormExplainEntity.getExplains();
                    if(Objects.nonNull(explains)){
                        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explains, null);
                        fieldAttr = explainMap.get(CustomerManagementEnum.PHONE.getAttr());
                    }
                }
            }
        } else if (Objects.equals(handlerExplainInLinkItemDTO.getLinkBusinessType(),XbbRefTypeEnum.INVENTORY.getCode()) || Objects.equals(handlerExplainInLinkItemDTO.getLinkBusinessType(),XbbRefTypeEnum.TRANSFER.getCode())){
            // 调拨出库和盘亏出库有单据在审批中就不允许关联新建
            if (commonHelp.isOpenWorkFlow(corpid)) {
                BoolQueryBuilder boolQueryBuilder = boolQuery();
                boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
                boolQueryBuilder.filter(termQuery(OutstockEnum.getEsAttr4Keyword(OutstockEnum.REF_ID), linkDataId));
                Integer type = OutstockTypeEnum.getByBuisenssTypeInt(handlerExplainInLinkItemDTO.getLinkBusinessType());
                boolQueryBuilder.filter(termQuery(OutstockEnum.getEsAttr4Keyword(OutstockEnum.TYPE), type));
                boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType())));
                long count = paasEsModel.count(boolQueryBuilder, IndexTypeEnum.IDX_SAAS_OUTSTOCK);
                if (count > 0) {
                    throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212040);
                }
            } else {
                Map<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put(StringConstant.CORPID,corpid);
                param.put(StringConstant.DEL,DelEnum.NORMAL.getDel());
                param.put("firstRefId", linkDataId);
                param.put("formDataId", 0);
                param.put("businessType", XbbRefTypeEnum.OTHER_OUTSTOCK.getCode());
                param.put("flowStatusIn", Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType()));
                param.put("sourceBusinessType", handlerExplainInLinkItemDTO.getLinkBusinessType());
                param.put("moduleType", 1);
                List<PaasProcessRelatedDataEntity> paasProcessRelatedDataList = paasProcessRelatedDataModel.findEntitys(param);
                if (!paasProcessRelatedDataList.isEmpty()) {
                    throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212040);
                }
            }

        }

        try {
            ContractEntityExt contractEntityExt = null;
            // 当业务类型为合同时去合同表查询数据
            if (Objects.equals(handlerExplainInLinkItemDTO.getLinkBusinessType(), XbbRefTypeEnum.CONTRACT.getCode())) {
                contractEntityExt = contractModel.getByKey(linkDataId, corpid);
            }
            for (FieldAttrEntity fieldAttrEntity : handlerExplainInLinkItemDTO.getExplainList()) {
                if (Objects.equals(fieldAttrEntity.getIsRedundant(),1)){
                    continue;
                }
                if (Objects.equals(fieldAttrEntity.getAttr(), OutstockEnum.REF_ID.getAttr())) {
                    RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(handlerExplainInLinkItemDTO.getLinkBusinessType());
                    switch (redundantTemplateTypeEnum){
                        case TRANSFER:
                            // 开启审批时关联新建走了addGet，导致可编辑
                            fieldAttrEntity.setEditable(0);
                            fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, serialNo, paasFormDataEntityExt.getFormId()));
                            break;
                        case CONTRACT:
                        case RETURNED_PURCHASE:
                        case INVENTORY:
                        case PRODUCTIONORDER:
                        case WORKORDER:
                            fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, serialNo, paasFormDataEntityExt.getFormId()));
                            break;
                        default:
                            throw new XbbException(TemplateErrorCodeEnum.API_ERROR_350006);
                    }
                }else if (Objects.equals(fieldAttrEntity.getAttr(), OutstockEnum.WAREHOUSE_ID.getAttr())) {
                    RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(handlerExplainInLinkItemDTO.getLinkBusinessType());
                    switch (redundantTemplateTypeEnum){
                        case INVENTORY:
                            fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, InventoryEnum.WAREHOUSE_ID.getAttr(), new JSONArray())));
                            fieldAttrEntity.setEditable(0);
                            break;
                        case TRANSFER:
                            fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, TransferEnum.OUT_WAREHOUSE_ID.getAttr(), new JSONArray())));
                            fieldAttrEntity.setEditable(0);
                            break;
                        case PRODUCTIONORDER:
                            fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, ProductionOrderEnum.OUT_WAREHOUSE_ID.getAttr(), new JSONArray())));
                            break;
                        default:
                            break;
                    }
                }else if (Objects.equals(fieldAttrEntity.getAttr(),OutstockEnum.TYPE.getAttr())){
                    String value = OutstockTypeEnum.getByBuisenssType(handlerExplainInLinkItemDTO.getLinkBusinessType());
                    for (ItemPoJo itemPoJo : fieldAttrEntity.getItems()){
                        if (Objects.equals(value, itemPoJo.getValue())){
                            itemPoJo.setChecked(true);
                        } else {
                            itemPoJo.setChecked(false);
                        }
                    }
                }else if (Objects.equals(fieldAttrEntity.getAttr(),OutstockEnum.PRODUCT.getAttr())){
                    Integer type = OutstockTypeEnum.getByBuisenssTypeInt(handlerExplainInLinkItemDTO.getLinkBusinessType());
                    List<BusinessProductEntity> businessProductEntityList = formDataValidateProductHelp.searchUnOutstockProduct(handlerExplainInLinkItemDTO.getCorpid(),handlerExplainInLinkItemDTO.getLinkDataId(),type, true);
                    List<OneKeyProduceProductPojo> productList = handlerExplainInLinkItemDTO.getProductList();
                    if (!productList.isEmpty()) {
                        Set<Long> oneKeyProduceProductSet = new HashSet<>();
                        productList.forEach(item -> oneKeyProduceProductSet.add(item.getId()));
                        businessProductEntityList.removeIf(businessProductEntity -> !oneKeyProduceProductSet.contains(businessProductEntity.getId()));
                    }
                    JSONArray productArray = formatOutstockLinkAdd(businessProductEntityList,fieldAttrEntity,type, handlerExplainInLinkItemDTO);
                    productHelp.enableSrialCheck(handlerExplainInLinkItemDTO.getCorpid(), productArray, handlerExplainInLinkItemDTO);
                    String defaultType = "";
                    if (Objects.nonNull(fieldAttrEntity.getDefaultAttr()) && Objects.nonNull(fieldAttrEntity.getDefaultAttr().getDefaultType())) {
                        defaultType = fieldAttrEntity.getDefaultAttr().getDefaultType();
                    }
                    fieldAttrEntity.setDefaultAttr(saasUpdateHelp.setDefaultValue(productArray));
                    if (Objects.nonNull(defaultType) && !defaultType.isEmpty()) {
                        fieldAttrEntity.getDefaultAttr().setDefaultType(defaultType);
                    }
                }else if (Objects.equals(handlerExplainInLinkItemDTO.getLinkBusinessType(),XbbRefTypeEnum.CONTRACT.getCode()) && Objects.nonNull(customerEntityExt)){
                    if (Objects.equals(fieldAttrEntity.getAttr(),ContractOutstockEnum.LINK_CUSTOMER.getAttr())){
                        fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(customerEntityExt.getId(), customerEntityExt.getData().getString(CustomerManagementEnum.NAME.getAttr())));
                    }else if (Objects.equals(fieldAttrEntity.getAttr(),ContractOutstockEnum.CUSTOMER_PHONE.getAttr())){
                        JSONArray jsonArray = customerEntityExt.getData().getJSONArray(CustomerManagementEnum.PHONE.getAttr());
                        if(Objects.equals(fieldAttr.getIsOpen(), BasicConstant.ZERO) || Objects.equals(fieldAttr.getVisible(), BasicConstant.ZERO)){
                            jsonArray = new JSONArray();
                        }
                        DefaultAttrPoJo defaultAttrPojo = saasUpdateHelp.getDefaultAttrPojo(jsonArray);
                        defaultAttrPojo.setRely(fieldAttrEntity.getDefaultAttr().getRely());
                        defaultAttrPojo.setDefaultType(fieldAttrEntity.getDefaultAttr().getDefaultType());
                        fieldAttrEntity.setDefaultAttr(defaultAttrPojo);
                    }else if (Objects.equals(fieldAttrEntity.getAttr(),ContractOutstockEnum.CUSTOMER_ADDRESS.getAttr()) && !Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(),handlerExplainInLinkItemDTO.getDistributorMark())){
                        DefaultAttrPoJo defaultAttrPojo = saasUpdateHelp.getDefaultAttrPojo(customerEntityExt.getData().getJSONObject(CustomerManagementEnum.ADDRESS.getAttr()));
                        defaultAttrPojo.setRely(fieldAttrEntity.getDefaultAttr().getRely());
                        defaultAttrPojo.setDefaultType(fieldAttrEntity.getDefaultAttr().getDefaultType());
                        fieldAttrEntity.setDefaultAttr(defaultAttrPojo);
                    }else if (Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(),handlerExplainInLinkItemDTO.getDistributorMark())){
                        // 订货单关联新建出库发货单带寄件人地址
                        if (Objects.equals(fieldAttrEntity.getAttr(),OrderOutStockEnum.LINK_PARTNER_RECEIVER.getAttr())){
                            fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(dataList.get(OrderEnum.LINK_PARTNER_RECEIVER.getAttr())));
                        }else if (Objects.equals(fieldAttrEntity.getAttr(),OrderOutStockEnum.RECEIPT_PHONE.getAttr())){
                            fieldAttrEntity.setDefaultAttr(saasUpdateHelp.setDefaultValue(dataList.get(OrderEnum.LINK_CONTACT_NUMBER.getAttr()).toString()));
                        }else if (Objects.equals(fieldAttrEntity.getAttr(),OrderOutStockEnum.RECEIPT_ADDRESS.getAttr())){
                            fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(dataList.getJSONObject(OrderEnum.SHIPPING_ADDRESS.getAttr())));
                        }
                    }
                    // 其他费用
                    if (StringUtils.equals(fieldAttrEntity.getAttr(), ContractOutstockEnum.OTHER_EXPENSE.getAttr()) && contractEntityExt != null) {
                        JSONObject data = contractEntityExt.getData();
                        BigDecimal zero = BigDecimal.ZERO;
                        BigDecimal outstockOtherExpense = data.containsKey(ContractEnum.OUTSTOCK_OTHER_EXPENSE.getAttr()) ? data.getBigDecimal(ContractEnum.OUTSTOCK_OTHER_EXPENSE.getAttr()) : zero;
                        BigDecimal otherExpense = data.containsKey(ContractEnum.OTHER_EXPENSE.getAttr()) ? data.getBigDecimal(ContractEnum.OTHER_EXPENSE.getAttr()) : zero;
                        fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(otherExpense.subtract(outstockOtherExpense)));
                    }
                    // 优惠金额
                    if (StringUtils.equals(fieldAttrEntity.getAttr(), ContractOutstockEnum.DISCOUNT_AMOUNT.getAttr()) && contractEntityExt != null) {
                        BigDecimal zero = BigDecimal.ZERO;
                        JSONObject data = contractEntityExt.getData();
                        BigDecimal outstockDiscountAmount = data.containsKey(ContractEnum.OUTSTOCK_DISCOUNT_AMOUNT.getAttr()) ? data.getBigDecimal(ContractEnum.OUTSTOCK_DISCOUNT_AMOUNT.getAttr()) : zero;
                        BigDecimal discountAmount = data.containsKey(ContractEnum.DISCOUNT_AMOUNT.getAttr()) ? data.getBigDecimal(ContractEnum.DISCOUNT_AMOUNT.getAttr()) : zero;
                        fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(discountAmount.subtract(outstockDiscountAmount)));
                    }
                    // 整单折扣率
                    if (StringUtils.equals(fieldAttrEntity.getAttr(), ContractOutstockEnum.WHOLE_ORDE_DISCOUNT_RATE.getAttr()) && contractEntityExt != null) {
                        fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(contractEntityExt.getData().get(ContractEnum.DISCOUNT.getAttr())));
                    }

                }else if (Objects.equals(handlerExplainInLinkItemDTO.getLinkBusinessType(),XbbRefTypeEnum.RETURNED_PURCHASE.getCode())){
                    if (Objects.equals(fieldAttrEntity.getAttr(),ReturnedPurchaseOutstockEnum.LINK_SUPPLIER.getAttr())){
                        fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, ReturnedPurchaseEnum.LINK_SUPPLIER.getAttr(), new JSONArray())));
                    }
                }else if (Objects.equals(handlerExplainInLinkItemDTO.getLinkBusinessType(),XbbRefTypeEnum.WORK_ORDER.getCode())){
                    if (Objects.equals(fieldAttrEntity.getAttr(),WorkOrderOutstockEnum.LINK_CUSTOMER.getAttr())){
                        fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, WorkOrderEnum.LINK_CUSTOMER.getAttr(), new JSONArray())));
                    }else if (Objects.equals(fieldAttrEntity.getAttr(),WorkOrderOutstockEnum.LINK_CONTACT.getAttr())){
                        fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, WorkOrderEnum.LINK_CONTACT.getAttr(), new JSONArray())));
                    }else if (Objects.equals(fieldAttrEntity.getAttr(),WorkOrderOutstockEnum.CUSTOMER_PHONE.getAttr())){
                        JSONArray jsonArray = dataList.getJSONArray(WorkOrderEnum.CONTACT_INFORMATION.getAttr());
                        if (Objects.isNull(fieldAttrEntity.getSubForm()) || Objects.isNull(fieldAttrEntity.getSubForm().getItems())){
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                        }
                        List<FieldAttrEntity> subExplainList = JSONArray.parseArray(JSON.toJSONString(fieldAttrEntity.getSubForm().getItems()), FieldAttrEntity.class);
                        Map<String,FieldAttrEntity> map = ExplainUtil.getExplainMapByList(subExplainList,"text_1");
                        FieldAttrEntity entity = map.get("text_1");
                        if (Objects.nonNull(entity)){
                            List<ItemPoJo> poJoList = entity.getItems();
                            if (Objects.nonNull(jsonArray)){
                                for (int i = 0; i < jsonArray.size(); i++) {
                                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                                    if (Objects.nonNull(jsonObject)){
                                        String value = jsonObject.getString("text_1");
                                        boolean exist = false;
                                        if (Objects.nonNull(poJoList)){
                                            for (int j = 0; j < poJoList.size(); j++) {
                                                ItemPoJo  itemPoJo = poJoList.get(j);
                                                if (Objects.equals(itemPoJo.getValue(),value)){
                                                    exist = true;
                                                }
                                            }
                                            if (!exist){
                                                jsonObject.put("text_1","");
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(jsonArray));
                    }else if (Objects.equals(fieldAttrEntity.getAttr(),WorkOrderOutstockEnum.CUSTOMER_ADDRESS.getAttr())){
                        fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(dataList.getJSONObject(WorkOrderEnum.ADDRESS.getAttr())));
                    }

                } else if (Objects.equals(handlerExplainInLinkItemDTO.getLinkBusinessType(),XbbRefTypeEnum.TRANSFER.getCode())){
                    if (Objects.equals(fieldAttrEntity.getAttr(),OutstockEnum.MEMO.getAttr())){
                        fieldAttrEntity.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(FastJsonHelper.getStringOrDefaultFromFormData(dataList, TransferEnum.MEMO.getAttr(), "")));
                    }
                }
            }
        } catch (XbbException e){
            throw e;
        } catch (Exception e) {
            LOG.error("outstockService.formatLinkAddExplain 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    private JSONArray formatOutstockLinkAdd(List<BusinessProductEntity> businessProductEntityList, FieldAttrEntity fieldAttrEntity, Integer type, HandlerExplainInLinkItemDTO handlerExplainInLinkItemDTO) throws XbbException {
        String corpid = handlerExplainInLinkItemDTO.getCorpid();
        UserVO loginUser = handlerExplainInLinkItemDTO.getLoginUser();
        Long formId = handlerExplainInLinkItemDTO.getFormId();
        Long sourceFormId = handlerExplainInLinkItemDTO.getSourceFormId();
        Long linkDataId = handlerExplainInLinkItemDTO.getLinkDataId();

        JSONArray productArray = new JSONArray();
        List<Long> dataIdList = new ArrayList<>();
        OutstockTypeEnum outstockTypeEnum = OutstockTypeEnum.getByCode(type);
//        boolean isSource = Arrays.asList(OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK, OutstockTypeEnum.CONTRACT_OUTSTOCK,OutstockTypeEnum.WORK_ORDER_OUTSTOCK).contains(outstockTypeEnum);
        LinkProductRelyEntity linkProductRelyEntity = linkProductRelyModel.getByAttrAndFormIdAndLinkFormId(corpid, OutstockEnum.PRODUCT.getAttr(), formId, sourceFormId, DelEnum.NORMAL.getDel());
        UserAndDepartmentGetDTO userAndDepartmentGetDTO = new UserAndDepartmentGetDTO();
        BeanUtil.copyProperties(handlerExplainInLinkItemDTO, userAndDepartmentGetDTO);
        UserAndDepartmentGetVO userAndDepartmentGetVO = userHelp.getUserDepartmentMap(userAndDepartmentGetDTO);
        Map<String, UserEntity> userMap = userAndDepartmentGetVO.getUserMap();
        Map<String, DepartmentEntity> departmentMap = userAndDepartmentGetVO.getDepartmentMap();
        JSONArray warehouseObj = new JSONArray();
        for (BusinessProductEntity entity : businessProductEntityList){
            JSONObject jsonObject = new JSONObject();
            jsonObject.put(OutstockProductEnum.PRODUCT.getAttr(),entity.getProductId());
            jsonObject.put(MultiUnitConstant.RATE, entity.getRate());
            jsonObject.put(OutstockProductEnum.NUM.getAttr(),entity.getProductNum());
            jsonObject.put(OutstockProductEnum.COST.getAttr(), Objects.isNull(entity.getCost()) ? 0D : entity.getCost());
            jsonObject.put(InstockProductEnum.UNIT.getAttr(), formDataValidateProductHelp.formatUnit(corpid,entity.getProductUnit()));
            jsonObject.put(OutstockProductEnum.MEMO.getAttr(),entity.getMemo());
            jsonObject.put(OutstockProductEnum.WAREHOUSE.getAttr(),entity.getWarehouseId());
            if (Objects.equals(type, OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())) {
                JSONObject data = entity.getData();
                if (Objects.nonNull(data)) {
                    jsonObject.put(SelectProductEnum.WAREHOUSE.getAttr(), data.get(SelectProductEnum.WAREHOUSE.getAttr()));
                    jsonObject.put(SelectProductEnum.BATCH.getAttr(), data.getString(SelectProductEnum.BATCH.getAttr()));
                    if (Objects.nonNull(data.getLong(SelectProductEnum.PRODUCE_DATE.getAttr())) && data.getLong(SelectProductEnum.PRODUCE_DATE.getAttr()) > 0L) {
                        jsonObject.put(SelectProductEnum.GUARANTEE_PERIOD.getAttr(), data.getLong(SelectProductEnum.GUARANTEE_PERIOD.getAttr()));
                    }
                    jsonObject.put(SelectProductEnum.PRODUCE_DATE.getAttr(), data.getLong(SelectProductEnum.PRODUCE_DATE.getAttr()));
                }
            }else {
                jsonObject.put(OutstockProductEnum.BATCH.getAttr(), entity.getBatch());
                jsonObject.put(OutstockProductEnum.PRODUCE_DATE.getAttr(),entity.getProduceDate());
                if (Objects.nonNull(entity.getProduceDate()) && entity.getProduceDate() > 0L) {
                    jsonObject.put(OutstockProductEnum.GUARANTEE_PERIOD.getAttr(),entity.getGuaranteePeriod());
                }
            }
            if (Objects.equals(OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode(),type)){
                jsonObject.put(ContractOutstockProductEnum.SELLING_PRICE.getAttr(), entity.getPrice());
                jsonObject.put(ContractOutstockProductEnum.DISCOUNT.getAttr(), entity.getDiscount());
                jsonObject.put(ContractOutstockProductEnum.SUBTOTAL.getAttr(), entity.getProductNum() * entity.getPrice());
                jsonObject.put(ContractOutstockProductEnum.PRICE.getAttr(), entity.getHistoricalPrice());
            }
            if (Objects.nonNull(entity.getRefProductId())) {
                jsonObject.put(BusinessConstant.REF_PRODUCT_ID, entity.getRefProductId());
            }
            jsonObject.put(BusinessConstant.PRODUCT_SUB_ID,0);
            productArray.add(jsonObject);
            dataIdList.add(entity.getProductId());
        }
        JSONObject productData = new JSONObject();
        productData.put(OutstockEnum.PRODUCT.getAttr(),productArray);
        //sku成本
        Map<Object,Double> costMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Object,Double> stockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //sku单价
        Map<Long,Double> priceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        boolean updatePrice = Objects.equals(type,OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode());

        //调拨、盘点、领料产品要拿仓库产品成本
        //合同、采购退货、工单、库存
        if (Objects.equals(outstockTypeEnum.getCode(),OutstockTypeEnum.TRANSFER_OUTSTOCK.getCode()) || Objects.equals(outstockTypeEnum.getCode(),OutstockTypeEnum.INVENTORY_OUTSTOCK.getCode())){
            // 调拨出库的关联产品取调拨单出库仓库的产品
            warehouseObj = formDataValidateProductHelp.getWarehouseObj(corpid,linkDataId,outstockTypeEnum.getBusinessType(),false);
            Long warehouseId = warehouseObj.getJSONObject(0).getLong("id");
            formDataValidateProductHelp.getSkuWarehouseOrBatchCost(productArray, warehouseId, corpid, costMap,stockMap);
        }else if(Objects.equals(outstockTypeEnum.getCode(),OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode()) || Objects.equals(outstockTypeEnum.getCode(),OutstockTypeEnum.MATERIEL_OUTSTOCK.getCode())){
            formDataValidateProductHelp.getSkuWarehouseOrBatchCost(productArray, corpid, costMap, stockMap);
        }else {
            costMap = formDataValidateProductHelp.getAllSkuCost(dataIdList,corpid);
        }
        if (updatePrice){
            priceMap = formDataValidateProductHelp.getSkuPrice(dataIdList,corpid);
        }
        //分仓库存和成本
        Map<Long,Map<String,JSONObject>> productMap = formDataValidateProductHelp.getWarehouseMap(dataIdList,corpid);
        JSONArray newProductArray = formDataValidateProductHelp.otherProductToAnother(productData,fieldAttrEntity,OutstockEnum.PRODUCT.getAttr(),OutstockEnum.PRODUCT.getAttr(),corpid, loginUser, handlerExplainInLinkItemDTO.getBusinessType(), handlerExplainInLinkItemDTO.getLinkBusinessType());
        // 关联产品自定义字段联动
        DefaultAttrPoJo defaultAttr = fieldAttrEntity.getDefaultAttr();
        String defaultType = defaultAttr.getDefaultType();
        // 源单解释
        Map<String, FieldAttrEntity> sourceExplainMap = null;
        // 当前表单解释
        Map<String, FieldAttrEntity> thisExplainMap = null;
        // 当前表单某个关联产品解释
        Map<String, FieldAttrEntity> subThisExplainMap = null;
        // 源单某个关联产品解释
        Map<String, FieldAttrEntity> subSourceExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 当前表单某个关联产品子字段与源单某个关联产品对应关系
        Map<String, String> thisToTarget = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (Objects.nonNull(defaultType) && Objects.equals(defaultType, DefaultTypeEnum.PRODUCT_DATA_RELY.getAlias()) && Objects.nonNull(linkProductRelyEntity)) {
            // 源数据表单
            PaasFormExplainEntity paasFormExplainEntity = proFormHelp.getExplainEntity(corpid, linkProductRelyEntity.getSourceFormId(), linkProductRelyEntity.getSourceBusinessType());
            List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
            sourceExplainMap = ExplainUtil.getExplainMapByList(explainList, null);
            // 当前表单解释
            PaasFormExplainEntity displayFormExplain = proFormHelp.getExplainEntity(corpid, linkProductRelyEntity.getFormId(), linkProductRelyEntity.getBusinessType());
            thisExplainMap = ExplainUtil.getExplainMap(displayFormExplain.getExplains(), null);
            subThisExplainMap = businessProductService.getProductRelyMap(OutstockEnum.PRODUCT.getAttr(), linkProductRelyEntity, sourceExplainMap, thisExplainMap, subSourceExplainMap, thisToTarget);
            for (BusinessProductEntity entity : businessProductEntityList){
                JSONObject entityData = entity.getData();
                if (Objects.nonNull(entityData) && !thisToTarget.isEmpty()) {
                    ParseSingleRowDataDTO parseSingleRowDataDTO = new ParseSingleRowDataDTO();
                    parseSingleRowDataDTO.setDataJsonObject(entityData);
                    parseSingleRowDataDTO.setUserMap(userMap);
                    parseSingleRowDataDTO.setDepartmentMap(departmentMap);
                    parseSingleRowDataDTO.setExplainMap(subSourceExplainMap);
                    ParseSingleRowDataVO parseSingleRowDataVO = formDataUpdateGetAnalysisDataHelp.parseSingleRowData(parseSingleRowDataDTO);
                    if (Objects.isNull(parseSingleRowDataVO)) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PARSE_SINGLE_ROW_DATA_FAILED);
                    }
                    JSONObject result = parseSingleRowDataVO.getResult();
                    JSONObject thisData = businessProductService.formatThisFormData(subThisExplainMap, thisToTarget, result);
                    for (int i = 0; i < newProductArray.size(); i++) {
                        JSONObject jsonObject = newProductArray.getJSONObject(i);
                        if (Objects.equals(jsonObject.getLongValue(BusinessConstant.REF_PRODUCT_ID), entity.getRefProductId())) {
                            jsonObject.putAll(thisData);
                            break;
                        }
                    }
                }
            }
        }
        for (int i = 0;i < newProductArray.size();i++){
            JSONObject jsonObject = newProductArray.getJSONObject(i);
            JSONObject product = jsonObject.getJSONObject(SelectProductEnum.PRODUCT.getAttr());
            Long productId = product.getLong("dataId");
            JSONObject sourceData = new JSONObject();
            Map<String, JSONObject> warehouseMap = productMap.getOrDefault(productId, new HashMap<>());
            sourceData.put("warehouse", warehouseMap);
            product.put("sourceData",sourceData);
            String batch = jsonObject.getString(SelectProductEnum.BATCH.getAttr());
            Long warehouseId = 0L;
            double rate = Objects.nonNull(jsonObject.getDouble(MultiUnitConstant.RATE)) ? jsonObject.getDouble(MultiUnitConstant.RATE) : 1D;
            if (Objects.equals(outstockTypeEnum.getCode(), OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode()) || Objects.equals(outstockTypeEnum.getCode(), OutstockTypeEnum.MATERIEL_OUTSTOCK.getCode())) {
                //采购退货入库和生产领料每个产品的仓库可能不一样
                if (Objects.nonNull(jsonObject.getLong(SelectProductEnum.WAREHOUSE.getAttr()))) {
                    warehouseId = jsonObject.getLong(SelectProductEnum.WAREHOUSE.getAttr());
                    JSONArray singleWarehouseObj = new JSONArray();
                    JSONObject returnWarehouseObj = new JSONObject();
                    returnWarehouseObj.put("id", jsonObject.getLong(SelectProductEnum.WAREHOUSE.getAttr()));
                    returnWarehouseObj.put("name", warehouseMap.getOrDefault(jsonObject.getString(SelectProductEnum.WAREHOUSE.getAttr()), new JSONObject()).getString(ProductEnum.WAREHOUSE.getSaasAttr()));
                    singleWarehouseObj.add(returnWarehouseObj);
                    jsonObject.put(OutstockProductEnum.WAREHOUSE.getAttr(), singleWarehouseObj);
                }
            }else {
                jsonObject.put(OutstockProductEnum.WAREHOUSE.getAttr(), warehouseObj);
                if (!warehouseObj.isEmpty()) {
                    warehouseId = warehouseObj.getJSONObject(0).getLong("id");
                }
            }
            //分为取批次成本丶库存和分仓成本丶库存
            Object key;
            if (StringUtil.isNotEmpty(batch)) {
                key = formDataValidateProductHelp.getBatchKey(productId, warehouseId, batch, jsonObject.getLong(SelectProductEnum.PRODUCE_DATE.getAttr()), FastJsonHelper.getLongOrDefaultFromFormData(jsonObject, SelectProductEnum.GUARANTEE_PERIOD.getAttr(), 0L) * TimeConstant.SECONDS_PER_DAY);
            }else {
                key = productId + "_" + warehouseId;
            }

            if (Objects.equals(outstockTypeEnum.getCode(),OutstockTypeEnum.TRANSFER_OUTSTOCK.getCode()) || Objects.equals(outstockTypeEnum.getCode(),OutstockTypeEnum.INVENTORY_OUTSTOCK.getCode()) || Objects.equals(outstockTypeEnum.getCode(),OutstockTypeEnum.MATERIEL_OUTSTOCK.getCode()) || Objects.equals(outstockTypeEnum.getCode(),OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
                //分为取批次库存和分仓库存
                if (Objects.nonNull(stockMap.get(key))) {
                    jsonObject.put(OutstockProductEnum.STOCK.getAttr(), stockMap.get(key));
                }
            }
            if (Objects.equals(outstockTypeEnum.getCode(),OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode())){
//                jsonObject.put(OutstockProductEnum.COST.getAttr(), jsonObject);
                JSONObject data = product.getJSONObject("data");
                data.put(SelectProductEnum.SOURCE_PRICE.getAttr(),jsonObject.get(SelectProductEnum.COST.getAttr()));
            }else {
                //分为取批次成本和分仓成本
                if (Objects.nonNull(jsonObject.get(ProductConstant.SELLING_PRICE_MAP))) {
                    JSONObject sellingMap = jsonObject.getJSONObject(ProductConstant.SELLING_PRICE_MAP);
                    if (!Objects.equals(outstockTypeEnum.getCode(),OutstockTypeEnum.MATERIEL_OUTSTOCK.getCode())){
                        sellingMap.put(OutstockProductEnum.COST.getAttr(), Arith.mul(rate, costMap.getOrDefault(key, 0D)));
                    }else {
                        sellingMap.put(OutstockProductEnum.COST.getAttr(), costMap.getOrDefault(key, 0D));
                    }
                }
                jsonObject.put(OutstockProductEnum.COST.getAttr(), Arith.mul(rate, costMap.getOrDefault(key, 0D)));
            }
            if (Objects.equals(outstockTypeEnum.getCode(),OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())){
                JSONObject data = product.getJSONObject("data");
                data.put(SelectProductEnum.SOURCE_PRICE.getAttr(),jsonObject.get(SelectProductEnum.SELLING_PRICE.getAttr()));
            }
            if (updatePrice && Objects.isNull(jsonObject.get(ContractOutstockProductEnum.PRICE.getAttr()))){
                jsonObject.put(ContractOutstockProductEnum.PRICE.getAttr(), priceMap.getOrDefault(productId, 0D));
            }
            JSONObject batchJson = new JSONObject();
            if (!StringUtil.isEmpty(batch)) {
                batchJson.put("value", batch);
                batchJson.put("text", batch);
                jsonObject.put(OutstockProductEnum.BATCH.getAttr(),batchJson);
            }
            jsonObject.put(OutstockProductEnum.TOTAL_COST.getAttr(),jsonObject.getDouble(OutstockProductEnum.COST.getAttr()) * jsonObject.getDouble(OutstockProductEnum.NUM.getAttr()));
            if (Objects.nonNull(jsonObject.get(SelectProductEnum.PRODUCE_DATE.getAttr())) && Objects.nonNull(jsonObject.getLong(SelectProductEnum.GUARANTEE_PERIOD.getAttr()))) {
                jsonObject.put(OutstockProductEnum.EXPIRE_DATE.getAttr(), jsonObject.getLong(SelectProductEnum.PRODUCE_DATE.getAttr()) + jsonObject.getLong(SelectProductEnum.GUARANTEE_PERIOD.getAttr()) * TimeConstant.SECONDS_PER_DAY);
            }
        }
        return newProductArray;
    }

    @Override
    public FormDataAddDTO formatExcelValue(ImportFormDataDTO importFormDataDTO, List<CellTitlePojo> titlePojoList, RowGroupPojo rowGroupPojo, List<FieldAttrEntityForImport> fieldAttrList) throws XbbException {
        FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
        String corpid = importFormDataDTO.getCorpid();
        BeanUtil.copyProperties(importFormDataDTO, formDataAddDTO);
        // data 数据
        JSONObject dataJson = new JSONObject();
        List<List<CellValuePojo>> rowValueList = rowGroupPojo.getRowValueList();
        // 分组的第一条数据作为给实体对象赋值的数据
        List<CellValuePojo> cellValueList = rowValueList.get(0);
        Integer businessType = importFormDataDTO.getBusinessType();
        Long refId = 0L;
        // 上游产品信息
        FieldAttrEntityForImport sheetNoAttrEntity = null;
        FieldAttrEntityForImport linkCustomerAttr = null;
        for (FieldAttrEntityForImport item : fieldAttrList) {
            if (Objects.equals(item.getAttr(), OutstockEnum.SHEET_NO.getAttr())) {
                sheetNoAttrEntity = item;
            } else if (Objects.equals(item.getAttr(), ContractOutstockEnum.LINK_CUSTOMER.getAttr())) {
                linkCustomerAttr = item;
            }
        }
        Long linkCustomerId = 0L;
        if (Objects.nonNull(linkCustomerAttr)) {
            linkCustomerId = importHelper.formatLinkCustomer2CustomerId(titlePojoList, dataJson, rowValueList, linkCustomerAttr);
        }
        // 遍历数据
        for (FieldAttrEntityForImport fieldAttrEntityForImport : fieldAttrList) {
            String attr = fieldAttrEntityForImport.getAttr();
            Integer fieldType = fieldAttrEntityForImport.getFieldType();
            String attrName = fieldAttrEntityForImport.getAttrName();
            Integer columnIndex = importHelper.getColumnIndexByTitle(titlePojoList, attrName, null);
            Object cellValue = importHelper.getValueByColumnIndex(cellValueList, columnIndex);

            if (Objects.equals(attr, ContractOutstockEnum.LINK_CUSTOMER.getAttr())) {

            } else if (Objects.equals(attr, OutstockEnum.PRODUCT.getAttr())) {
                importHelper.formatCommonProduct(titlePojoList, dataJson, rowValueList, fieldAttrEntityForImport, businessType, corpid);
            } else if (Objects.equals(fieldType, FieldTypeEnum.SUB_FORM.getType())) {
                importHelper.formatSubFormValue4Import(rowValueList, titlePojoList, importFormDataDTO, fieldAttrEntityForImport, dataJson);
            } else if (Objects.equals(attr, OutstockEnum.REF_ID.getAttr())) {
                if (Objects.equals(businessType, XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
                    refId = importHelper.formatRelyBusiness(linkCustomerId, dataJson, fieldAttrEntityForImport, cellValue, ContractEnum.LINK_CUSTOMER.getAttr());
                }
            } else if (Objects.equals(attr, OutstockEnum.MANAGER_ID.getAttr())) {
                Map<String, Object> userMap = fieldAttrEntityForImport.getLinkBusinessMap();
                for (Map.Entry<String, Object> entry: userMap.entrySet()) {
                    if (Objects.equals(cellValue.toString(), entry.getKey())) {
                        ReturnUserAndDepartmentPojo returnUserAndDepartmentPojo = new ReturnUserAndDepartmentPojo();
                        returnUserAndDepartmentPojo.setId(entry.getValue().toString());
                        formDataAddDTO.setOwnerId(Collections.singletonList(returnUserAndDepartmentPojo));
                        break;
                    }
                }
            } else if (Objects.equals(attr, OutstockEnum.WAREHOUSE_ID.getAttr())) {
                importHelper.formatWareHouse4Import(dataJson, fieldAttrEntityForImport, attr, cellValue);
            } else if (Objects.equals(fieldType, FieldTypeEnum.SERIALNO.getType())) {
                if (Objects.isNull(cellValue) || StringUtil.isEmpty(cellValue.toString())) {
                    throw new XbbException(BuinessDefaultErrorCodeEnum.API_ERROR_200022);
                }
                formDataAddDTO.setSerialNo(cellValue.toString());
            } else if (Objects.equals(attr, OutstockEnum.TYPE.getAttr()) && Objects.equals(businessType, XbbRefTypeEnum.OTHER_OUTSTOCK.getCode())){
                if (!Objects.equals(cellValue.toString(), OutstockTypeEnum.OTHER_OUTSTOCK.getName())) {
                    throw new XbbException(ImportErrorCodeEnum.API_ERROR_235038, String.format(ImportErrorCodeEnum.API_ERROR_235038.getMsg(), OutstockTypeEnum.OTHER_OUTSTOCK.getName()));
                }
                dataJson.put(attr, String.valueOf(OutstockTypeEnum.OTHER_OUTSTOCK.getCode()));
            } else if (Objects.equals(attr, OutstockEnum.TIME.getAttr())) {
                Long time = DateTimeUtil.getExcelTime(cellValue.toString());
                if (time == 0L) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.FORMAT_INVALID, fieldAttrEntityForImport.getAttrName());
                }
                SettleAccountsEntity accountsEntity = settleAccountsModel.getLastSettleAccounts(corpid);
                //校验日期是否受结账限制
                if (Objects.nonNull(accountsEntity) && Objects.nonNull(accountsEntity.getCheckOutTime())) {
                    if (time <= DateTimeUtil.getTodayEndInt(accountsEntity.getCheckOutTime())) {
                        throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212034);
                    }
                }
                dataJson.put(attr, time);
            } else if (Objects.equals(businessType, XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode()) && Objects.equals(importFormDataDTO.getDistributorMark(), DistributorMarkEnum.DISTRIBUTOR.getCode()) &&
                    (Objects.equals(attr, OrderOutStockEnum.LINK_PARTNER_RECEIVER.getAttr()) || Objects.equals(attr, OrderOutStockEnum.SEND_NAME.getAttr()))) {
                // 收货人
                boolean isMatchReceiver = false;
                Map<Long, List<ContractSubDataExt>> addressMap = fieldAttrEntityForImport.getShippingAddressMap();
                if (addressMap != null) {
                    List<ContractSubDataExt> addressList = addressMap.get(linkCustomerId);
                    for (ContractSubDataExt contractSubDataExt : addressList) {
                        JSONObject subDataObj = contractSubDataExt.getData();
                        if (Objects.equals(subDataObj.getString(DistributorAddressEnum.RECEIVER.getAttr()), Objects.toString(cellValue))) {
                            subDataObj.put("id", contractSubDataExt.getId());
                            subDataObj.put("name", Objects.toString(cellValue));
                            subDataObj.put("dataId", contractSubDataExt.getDataId());
                            subDataObj.put("formId", contractSubDataExt.getFormId());
                            JSONArray receiverArray = new JSONArray();
                            receiverArray.add(subDataObj);
                            dataJson.put(attr, receiverArray);
                            if (Objects.equals(attr, OrderOutStockEnum.LINK_PARTNER_RECEIVER.getAttr())) {
                                dataJson.put(OrderOutStockEnum.RECEIPT_PHONE.getAttr(), subDataObj.getString(DistributorAddressEnum.PHONE.getAttr()));
                                dataJson.put(OrderOutStockEnum.RECEIPT_ADDRESS.getAttr(), subDataObj.getJSONObject(DistributorAddressEnum.ADDRESS.getAttr()));
                            }
                            if (Objects.equals(attr, OrderOutStockEnum.SEND_NAME.getAttr())) {
                                dataJson.put(OrderOutStockEnum.SEND_PHONE.getAttr(), subDataObj.getString(DistributorAddressEnum.PHONE.getAttr()));
                                dataJson.put(OrderOutStockEnum.SEND_ADDRESS.getAttr(), subDataObj.getJSONObject(DistributorAddressEnum.ADDRESS.getAttr()));
                            }
                            isMatchReceiver = true;
                            break;
                        }
                    }
                }
                if (!isMatchReceiver) {
                    throw new XbbException(ImportErrorCodeEnum.API_ERROR_235055);
                }
            } else {
                if (Objects.isNull(cellValue) || StringUtil.isEmpty(cellValue.toString())) {
                    continue;
                }
                if (ImportHelper.commonHandleFieldType.contains(fieldAttrEntityForImport.getFieldType())) {
                    importHelper.formatCommonField(dataJson, fieldAttrEntityForImport, cellValue);
                } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA.getType())) {
                    importHelper.formatLinkData(cellValue, fieldAttrEntityForImport, dataJson);
                } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA_MULTI.getType())) {
                    importHelper.formatLinkDataMulti(cellValue, importFormDataDTO, fieldAttrEntityForImport, dataJson);
                } else {
                    dataJson.put(attr, cellValue);
                }
            }
        }
        if (Objects.equals(businessType, XbbRefTypeEnum.OTHER_OUTSTOCK.getCode())) {
            JSONArray productJsonArray = dataJson.getJSONArray(ContractOutstockEnum.PRODUCT.getAttr());
            Double rate = 1D;
            for (int i = 0; i < productJsonArray.size(); i++) {
                JSONObject jsonObject = productJsonArray.getJSONObject(i);
                Integer enableMultiUnit = jsonObject.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getSaasAttr());
                if (Objects.equals(BasicConstant.ONE, enableMultiUnit)){
                    JSONObject unitObject = (JSONObject) jsonObject.get(ProductEnum.UNIT.getAttr());
                    List<UnitItemPoJo> transformUnitRate = (List<UnitItemPoJo>)jsonObject.get(ProductConstant.TRANSFORM_UNIT_RATE);
                    for (UnitItemPoJo unitItemPoJo : transformUnitRate) {
                        if (Objects.equals(unitObject.getLong(MultiUnitConstant.VALUE), unitItemPoJo.getValue())) {
                            rate = unitItemPoJo.getRate();
                            break;
                        }
                    }
                    jsonObject.put(SelectProductEnum.COST.getAttr(), Arith.mul(jsonObject.getDouble(SelectProductEnum.COST.getAttr()), rate));
                    jsonObject.put(SelectProductEnum.TOTAL_COST.getAttr(), Arith.mul(jsonObject.getDouble(SelectProductEnum.COST.getAttr()), jsonObject.getDouble(SelectProductEnum.NUM.getAttr())));
                }
            }
        }
        if (Objects.equals(businessType, XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
            Double totalSalePrice = 0D;
            if (Objects.nonNull(sheetNoAttrEntity) && Objects.nonNull(sheetNoAttrEntity.getLinkBusinessMap()) && sheetNoAttrEntity.getLinkBusinessMap().containsKey(refId.toString())) {
                List<ContractProductEntity> productEntityList = (List<ContractProductEntity>) sheetNoAttrEntity.getLinkBusinessMap().get(refId.toString());
                Map<Long, ContractProductEntity> refProduct = new HashMap<>(productEntityList.size());
                for (ContractProductEntity item : productEntityList) {
                    if (refProduct.containsKey(item.getProductId())) {
                        throw new XbbException(ImportErrorCodeEnum.API_ERROR_235036);
                    } else {
                        refProduct.put(item.getProductId(), item);
                    }
                }
                JSONArray productJsonArray = dataJson.getJSONArray(ContractOutstockEnum.PRODUCT.getAttr());
                Set<Long> repeatLineList = new HashSet<>();
                for (int i = 0; i < productJsonArray.size(); i++) {
                    JSONObject jsonObject = productJsonArray.getJSONObject(i);
                    Integer enableMultiUnit = jsonObject.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getSaasAttr());
                    Long productId = jsonObject.getJSONObject(SelectProductEnum.PRODUCT.getAttr()).getLong(StringConstant.DATA_ID);
                    if (refProduct.containsKey(productId)) {
                        ContractProductEntity contractProductEntity = refProduct.get(productId);
                        Long refProductId = contractProductEntity.getId();
                        if (repeatLineList.contains(refProductId)) {
                            throw new XbbException(ImportErrorCodeEnum.API_ERROR_235041);
                        }
                        boolean isSwitchUnit = false;
                        Double rate = 1D;
                        if (Objects.equals(BasicConstant.ONE, enableMultiUnit)){
                            JSONObject unitObject = (JSONObject) jsonObject.get(ProductEnum.UNIT.getAttr());
                            List<UnitItemPoJo> transformUnitRate = (List<UnitItemPoJo>)jsonObject.get(ProductConstant.TRANSFORM_UNIT_RATE);
                            Long baseValue = null;
                            for (UnitItemPoJo unitItemPoJo : transformUnitRate) {
                                if (Objects.equals(unitItemPoJo.getIsBase(), 1)) {
                                    baseValue = unitItemPoJo.getValue();
                                }
                                if (Objects.equals(unitObject.getLong(MultiUnitConstant.VALUE), unitItemPoJo.getValue())) {
                                    rate = unitItemPoJo.getRate();
                                }
                            }
                            Set<Long> unitIdSet = new HashSet<>();
                            if (!Objects.equals(unitObject.getLong(BasicConstant.VALUE) , contractProductEntity.getBusinessUnit() == null ? contractProductEntity.getProductUnit() : contractProductEntity.getBusinessUnit())){
                                isSwitchUnit = true;
                            }
                            unitIdSet.add(contractProductEntity.getBusinessUnit());
                            unitIdSet.add(baseValue);
                            if (!unitIdSet.contains(unitObject.getLong(BasicConstant.VALUE))){
                                throw new XbbException(ImportErrorCodeEnum.API_ERROR_235050, String.format(ImportErrorCodeEnum.API_ERROR_235050.getMsg(), contractProductEntity.getProductName() + "(" + contractProductEntity.getSpecification() +")"));
                            }
                        }
                        repeatLineList.add(refProductId);
                        jsonObject.put(BusinessConstant.REF_PRODUCT_ID, refProductId);
                        jsonObject.put(SelectProductEnum.SELLING_PRICE.getAttr(), contractProductEntity.getPrice());
                        if (!isSwitchUnit) {
                            JSONObject priceData = contractProductEntity.getPriceData();
                            if (Objects.nonNull(priceData) && priceData.containsKey(SelectProductEnum.SELLING_PRICE.getAttr())) {
                                jsonObject.put(SelectProductEnum.SELLING_PRICE.getAttr(), priceData.getDouble(SelectProductEnum.SELLING_PRICE.getAttr()));
                            }
                            if (Objects.nonNull(priceData) && priceData.containsKey(SelectProductEnum.PRICE.getAttr())) {
                                jsonObject.put(SelectProductEnum.PRICE.getAttr(), priceData.getDouble(SelectProductEnum.PRICE.getAttr()));
                            } else {
                                jsonObject.put(SelectProductEnum.PRICE.getAttr(), contractProductEntity.getHistoricalPrice());
                            }
                            jsonObject.put(SelectProductEnum.DISCOUNT.getAttr(), contractProductEntity.getDiscount());
                        } else {
                            jsonObject.put(SelectProductEnum.DISCOUNT.getAttr(), Arith.mul(Arith.div(jsonObject.getDouble(SelectProductEnum.SELLING_PRICE.getAttr()), jsonObject.getDouble(SelectProductEnum.PRICE.getAttr()), 2), 100));
                        }
                        jsonObject.put(SelectProductEnum.SUBTOTAL.getAttr(), Arith.mul(jsonObject.getDouble(SelectProductEnum.SELLING_PRICE.getAttr()), jsonObject.getDouble(SelectProductEnum.NUM.getAttr())));
                        jsonObject.put(SelectProductEnum.COST.getAttr(), Arith.mul(jsonObject.getDouble(SelectProductEnum.COST.getAttr()), rate));
                        totalSalePrice = Arith.add(totalSalePrice, refProduct.get(productId).getPrice() == null ? 0 : refProduct.get(productId).getPrice()*jsonObject.getDouble(SelectProductEnum.NUM.getAttr()));
                    } else {
                        throw new XbbException(ImportErrorCodeEnum.API_ERROR_235031);
                    }
                }
            } else {
                throw new XbbException(ImportErrorCodeEnum.API_ERROR_235010);
            }
            // 处理出库产品之外字段
            Double otherExpense = 0D;
            if (dataJson.containsKey(ContractOutstockEnum.OTHER_EXPENSE.getAttr())) {
                otherExpense = dataJson.getDouble(ContractOutstockEnum.OTHER_EXPENSE.getAttr());
            }
            dataJson.put(ContractOutstockEnum.PRODUCT_TOTAL.getAttr(), totalSalePrice);
            dataJson.put(ContractOutstockEnum.TOTAL_MONEY.getAttr(), Arith.add(totalSalePrice, otherExpense));
        }
        formDataAddDTO.setDataList(dataJson);
        return formDataAddDTO;
    }


    @Override
    public void formatExportValue(List<PaasFormDataEntityExt> paasFormDataESList, FormDataListDTO formDataListDTO, List<FieldAttrEntityForImport> fieldAttrList) throws XbbException {
        // 所有产品map
        List<Long> idList = new ArrayList<>();
        paasFormDataESList.forEach(item -> idList.add(item.getDataId()));
        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        params.put(ParameterConstant.CORPID, formDataListDTO.getCorpid());
        params.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        List<ProductEntityExt> productList = productModel.findEntitys(params);
        Map<Long, ProductEntityExt> productMap = new HashMap<>();
        productList.forEach(item -> productMap.put(item.getId(), item));
        // 出库关联产品map
        params.put("outstockIdIn", idList);
        params.put("orderByStr","sort");
        List<OutstockProductEntity> outstockProductList = outstockProductModel.findEntitys(params);
        Map<Long, List<OutstockProductEntity>> outstockProductMap = new HashMap<>();
        outstockProductList.forEach(item -> {
            Long refId = item.getOutWarehouseId();
            if (outstockProductMap.containsKey(refId)) {
                outstockProductMap.get(refId).add(item);
            } else {
                List<OutstockProductEntity> productEntityList = new ArrayList<>();
                productEntityList.add(item);
                outstockProductMap.put(refId, productEntityList);
            }
        });

        // 所有仓库map
        params.remove("outstockIdIn");
        params.remove("orderByStr");
        List<WarehouseEntityExt> warehouseList = warehouseModel.findEntitys(params);
        Map<Long, WarehouseEntityExt> warehouseMap = new HashMap<>();
        warehouseList.forEach(item -> warehouseMap.put(item.getId(), item));

        // 产品，库存产品
        FieldAttrEntityForImport productFieldAttr = new FieldAttrEntityForImport();
        for (FieldAttrEntityForImport item : fieldAttrList) {
            if (Objects.equals(item.getAttr(), OutstockEnum.PRODUCT.getAttr())) {
                productFieldAttr = item;
            }
        }
        // 精度
        SubFormPoJo subFormPoJo = productFieldAttr.getSubForm();
        List<? extends FieldAttrEntity> subFieldAttrList = new ArrayList<>();
        if (Objects.nonNull(subFormPoJo)){
            subFieldAttrList = subFormPoJo.getItems();
        }
        int accuracy = 2;
        boolean costVisible = false;
        boolean costOpen = false;
        FieldAttrEntity costFieldAttrEntity = new FieldAttrEntity();
        for (FieldAttrEntity item : subFieldAttrList) {
            if (Objects.equals(item.getAttr(), SelectProductEnum.COST.getAttr())) {
                accuracy = item.getAccuracy() == null ? 2 : item.getAccuracy();
                HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
                BeanUtil.copyProperties(formDataListDTO, handlerExplainDTO, false);
                costVisible = !ExplainUtil.isFieldNeedHide(item, handlerExplainDTO);
                costOpen = Objects.equals(item.getIsOpen(), 1);
                costFieldAttrEntity = item;
                break;
            }
        }
        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
        handlerExplainDTO.setLoginUser(formDataListDTO.getLoginUser());
        handlerExplainDTO.setUserId(formDataListDTO.getUserId());

        Map<String, MultiUnitItemPoJo> groupBaseUnitStringMap = relativeProductHelp.getGroupBaseUnitStringMap(formDataListDTO.getCorpid());

        // 暂时只处理产品
        for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataESList) {
            JSONObject formDataObj = paasFormDataEntityExt.getData();
            String productAttr = productFieldAttr.getAttr();
            Long dataId = paasFormDataEntityExt.getDataId();
            handlerExplainDTO.setCreatorId(paasFormDataEntityExt.getCreatorId());
            handlerExplainDTO.setOwnerId(Arrays.asList(paasFormDataEntityExt.getOwnerId()));
            if ( costOpen && costVisible) {
                if (ExplainUtil.invisibleOfScope(costFieldAttrEntity,handlerExplainDTO)) {
                    costVisible = false;
                }
            }
            List<OutstockProductEntity> outstockProductEntityList = outstockProductMap.get(dataId);
            if (outstockProductEntityList == null || outstockProductEntityList.size() == 0) {
                formDataObj.put(productAttr, new JSONArray());
                continue;
            }
            JSONArray productArray = new JSONArray();
            for (OutstockProductEntity outstockProductEntity : outstockProductEntityList) {
                Long productId = outstockProductEntity.getProductId();
                if (Objects.nonNull(outstockProductEntity.getPriceData()) && outstockProductEntity.getPriceData().size() > 0){
                    outstockProductEntity.getData().putAll(outstockProductEntity.getPriceData());
                }
                Double num = outstockProductEntity.getProductNum() == null ? 0 : outstockProductEntity.getProductNum();
                Long warehouseId = outstockProductEntity.getWarehouseId();
                Double salePrice = 0D;
                Double discount = outstockProductEntity.getDiscount();
                Double cost = 0D;
                if (Objects.isNull(outstockProductEntity.getPriceData())){
                    salePrice = outstockProductEntity.getProductPrice();
                    cost = outstockProductEntity.getCost() == null ? 0D : outstockProductEntity.getCost();
                }else {
                    salePrice = outstockProductEntity.getData().getDouble(SelectProductEnum.SELLING_PRICE.getAttr());
                    cost = outstockProductEntity.getData().getDouble(SelectProductEnum.COST.getAttr());
                    if (Objects.nonNull(outstockProductEntity.getBusinessUnit())){
                        num = outstockProductEntity.getBusinessNum();
                    }
                }
                // 默认保留两位小数
                cost = Arith.round(cost, accuracy);
                Double saleSubTotal = Arith.mul(num, (salePrice == null ? 0D : salePrice));
                // 产品信息转换
                JSONObject productObj = new JSONObject();
                if (Objects.nonNull(outstockProductEntity.getData())) {
                    productObj.putAll(outstockProductEntity.getData());
                }
                if (Objects.equals(formDataListDTO.getBusinessType(), XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
                    productObj.put(ContractOutstockProductEnum.SELLING_PRICE.getAttr(), salePrice);
                    productObj.put(ContractOutstockProductEnum.SUBTOTAL.getAttr(), saleSubTotal);
                    productObj.put(ContractOutstockProductEnum.DISCOUNT.getAttr(), discount);
                }
                importHelper.formatProduct4Export(productMap, warehouseMap, productId, num, warehouseId, productObj);
                productObj.put(SelectProductEnum.COST.getAttr(), cost);
                productObj.put(SelectProductEnum.TOTAL_COST.getAttr(), Arith.mul(cost, num));
                if (!costOpen || !costVisible) {
                    productObj.put(SelectProductEnum.COST.getAttr(), null);
                    productObj.put(SelectProductEnum.TOTAL_COST.getAttr(), null);
                }
                productArray.add(productObj);
                // 库存产品信息转换
                String batch = outstockProductEntity.getBatch();
                productObj.put(SelectProductEnum.BATCH.getAttr(), batch);
                Long guaranteePeriod = outstockProductEntity.getGuaranteePeriod();
                if (outstockProductEntity.getGuaranteePeriod() != null) {
                    Long guaranteePeriodDay = guaranteePeriod / 86400;
                    if (!Objects.equals(guaranteePeriodDay, 0L)) {
                        productObj.put(SelectProductEnum.GUARANTEE_PERIOD.getAttr(), guaranteePeriodDay);
                    }
                }
                Long produceDate = outstockProductEntity.getProduceDate();
                if (produceDate == null || produceDate == 0L) {
                    productObj.put(SelectProductEnum.PRODUCE_DATE.getAttr(), "");
                    productObj.remove(SelectProductEnum.GUARANTEE_PERIOD.getAttr());
                } else {
                    String produceDateStr = DateTimeUtil.getStringEpochSecond(produceDate, DateTimeUtil.SDFDate);
                    productObj.put(SelectProductEnum.PRODUCE_DATE.getAttr(), produceDateStr);
                    productObj.put(SelectProductEnum.EXPIRE_DATE.getAttr(), DateTimeUtil.getStringEpochSecond(produceDate + guaranteePeriod, DateTimeUtil.SDFDate));
                }
                //基本单位时直接塞入productUnit
                if (Objects.isNull(outstockProductEntity.getBusinessUnit())){
                    if (Objects.equals(productObj.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr()), BasicConstant.ONE)){
                        productObj.put(ProductEnum.UNIT.getAttr(), groupBaseUnitStringMap.getOrDefault(productObj.getString(ProductEnum.UNIT.getAttr()), new MultiUnitItemPoJo()).getBaseValue());
                        outstockProductEntity.setProductUnit(productObj.getString(ProductEnum.UNIT.getAttr()));
                    }
                    productObj.put(SelectProductEnum.NUM.getAttr(), outstockProductEntity.getProductNum());
                }else {
                    productObj.put(ProductEnum.UNIT.getAttr(), outstockProductEntity.getBusinessUnit());
                    productObj.put(SelectProductEnum.NUM.getAttr(), outstockProductEntity.getBusinessNum());
                }
                if(Objects.equals(productObj.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr()), BasicConstant.ONE)){
                    productObj.put(SelectProductEnum.BASIC_UNIT.getAttr(), outstockProductEntity.getProductUnit());
                    productObj.put(SelectProductEnum.BASIC_UNIT_NUM.getAttr(),  outstockProductEntity.getProductNum());
                }else {
                    productObj.put(SelectProductEnum.BASIC_UNIT.getAttr(), "");
                    productObj.put(SelectProductEnum.BASIC_UNIT_NUM.getAttr(), "");
                }


                String memo = outstockProductEntity.getMemo();
                productObj.put(SelectProductEnum.MEMO.getAttr(), memo);
            }
            formDataObj.put(productAttr, productArray);

            // 收货人 寄件人处理
            if (Objects.equals(formDataListDTO.getBusinessType(), XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode()) && Objects.equals(formDataListDTO.getDistributorMark(), DistributorMarkEnum.DISTRIBUTOR.getCode())) {
                formDataObj.put(OrderOutStockEnum.LINK_PARTNER_RECEIVER.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(formDataObj, OrderOutStockEnum.LINK_PARTNER_RECEIVER_HIDE.getAttr(), ""));
                formDataObj.put(OrderOutStockEnum.SEND_NAME.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(formDataObj, OrderOutStockEnum.LINK_SEND_HIDE.getAttr(), ""));
            }
        }
    }

    private void updateBatch(OutstockUpdateBatchDTO outstockUpdateBatchDTO) throws XbbException {
        try {
            List<UpdateDataEntity> updateDataList = new ArrayList<>();
            String corpid = outstockUpdateBatchDTO.getCorpid();
            outstockUpdateBatchDTO.getOutstockList().forEach((item)->{
                UpdateDataEntity updateDataEntity = ExplainUtil.getUpdateData(item.getId(), item.getData(), corpid);
                updateDataList.add(updateDataEntity);
            });
            if (!updateDataList.isEmpty()) {
                outstockModel.updateBatch(updateDataList, corpid);
            }
        } catch (Exception e) {
            LOG.error("outstockService.updateBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }





    @Override
    public JSONObject getFormatProductJsonArray(FormatOutstockProductDTO formatOutstockProductDTO) throws XbbException {
        // 获取属性
        String corpid = formatOutstockProductDTO.getCorpid();
        OutstockProductEntityExt outstockProductExt = formatOutstockProductDTO.getOutstockProductExt();
        Map<String, FieldAttrEntity> nowProductExplainMap = formatOutstockProductDTO.getNowProductExplainMap();
        JSONObject warehouseObj = outstockProductExt.getWarehouseObj();

        Long productId = outstockProductExt.getProductId();
        Long productWarehouseId = outstockProductExt.getWarehouseId();
        ProductEntityExt childProduct = productModel.getByKey(productId, corpid);
        boolean isCostFieldNeedHide = false;
        if (childProduct != null) {
            Long parentId = childProduct.getData().getLong(ProductEnum.PARENT_ID.getAttr());
            PaasFormDataEntityExt paasFormDataEsEntity = productModel.getByKey(parentId, corpid);
            if (paasFormDataEsEntity != null) {
                //协同团队
                Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                userTeamService.getUserIdMap(Collections.singletonList(parentId), corpid, XbbRefTypeEnum.PRODUCT.getCode(), false, mainUserMap, coUserMap);
                HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
                BeanUtil.copyProperties(formatOutstockProductDTO, handlerExplainDTO);
                handlerExplainDTO.setCreatorId(paasFormDataEsEntity.getCreatorId());
                handlerExplainDTO.setOwnerId(mainUserMap.getOrDefault(paasFormDataEsEntity.getDataId(), new ArrayList<>()));
                handlerExplainDTO.setCoUserId(coUserMap.getOrDefault(paasFormDataEsEntity.getDataId(), new ArrayList<>()));
                handlerExplainDTO.setExplainList(new ArrayList<>(nowProductExplainMap.values()));
                isCostFieldNeedHide = ExplainUtil.isFieldNeedHide(nowProductExplainMap.getOrDefault(ProductEnum.COST.getSaasAttr(), new FieldAttrEntity()), handlerExplainDTO);
            }
        }

        Long outstockProductExtId = outstockProductExt.getId();
        JSONArray attrArray = new JSONArray();
        JSONObject productObj = new JSONObject();

        ProductWarehouseMapDTO productWarehouseMapDTO = new ProductWarehouseMapDTO();
        BeanUtil.copyProperties(formatOutstockProductDTO, productWarehouseMapDTO);
        productWarehouseMapDTO.setAllWarehouse(0);
        productWarehouseMapDTO.setProductId(productId);
        ProductWarehouseMapVO productWarehouseMapVO = warehouseService.getSelectProductWarehouses(productWarehouseMapDTO);
        if (Objects.isNull(productWarehouseMapVO)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        Map<String, JSONArray> warehouseMap = productWarehouseMapVO.getProductWarehouseMap();
        JSONArray warehouseArray = warehouseMap.get("userWarehouseArray");

        // 获取关联产品需要展示的字段
        BusinessProductEnum businessProductEnum = BusinessProductEnum.getByCodeAndTargetCode(XbbRefTypeEnum.OUTSTOCK.getCode(), formatOutstockProductDTO.getBusinessType());
        List<RelativeProductEnum> businessProductEnumList = businessProductEnum.getList();
        for (RelativeProductEnum productEnum : businessProductEnumList) {
            String saasAttr = productEnum.getSaasAttr();
            FieldAttrEntity fieldAttrEntity = null;
            if (nowProductExplainMap.containsKey(saasAttr)) {
                fieldAttrEntity = nowProductExplainMap.get(saasAttr);
            }
            switch (productEnum) {
                case NAME:
                    JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(NAME, outstockProductExt.getProductName(), fieldAttrEntity));
                    break;
                case PRODUCT_NO:
                    JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(PRODUCT_NO, outstockProductExt.getProductNo(), fieldAttrEntity));
                    break;
                case BARCODE:
                    JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(BARCODE, outstockProductExt.getBarcode(), fieldAttrEntity));
                    break;
                case WAREHOUSE:
                    warehouseObj = warehouseObj == null ? new JSONObject() : warehouseObj;

                    JSONObject warehouseResultObj = saasUpdateHelp.formatSelectProduct4Show(WAREHOUSE, warehouseObj, fieldAttrEntity);
                    if(warehouseResultObj != null) {
                        warehouseResultObj.put("attrName", I18nMessageUtil.getMessage(StringConstant.OUT_WAREHOUSE));
                        warehouseResultObj.put("warehouseArray", warehouseArray);
                        attrArray.add(warehouseResultObj);
                    }
                    break;
                case NUM:
                    if(Objects.isNull(fieldAttrEntity)) {
                        fieldAttrEntity = new FieldAttrEntity();
                    }
                    FieldAttrEntity stockAttrEntity = nowProductExplainMap.get(ProductEnum.STOCK.getSaasAttr());
                    if(Objects.nonNull(stockAttrEntity)) {
                        fieldAttrEntity.setAccuracy(stockAttrEntity.getAccuracy());
                    }
                    JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(NUM, outstockProductExt.getProductNum(), fieldAttrEntity));
                    break;
                case COST:
                    JSONObject costObj = saasUpdateHelp.formatSelectProduct4Show(COST, outstockProductExt.getCost(), fieldAttrEntity);
                    if (costObj != null) {
                        costObj.put("attr", StringConstant.PRODUCT_COST);
                        if (isCostFieldNeedHide) {
                            costObj.put("hideCost", true);
                        }
                        attrArray.add(costObj);
                    }
                    break;
                case SPECIFICATION:
                    // 格式化规格
                    String specification = specificationModel.joinSpecification(outstockProductExt.getProductSpecification());
                    JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(SPECIFICATION, specification, fieldAttrEntity));
                    break;
                case STOCK:
                    if (Objects.isNull(productWarehouseId)) {
                        JSONObject stockObj = saasUpdateHelp.formatSelectProduct4Show(STOCK, outstockProductExt.getStock(), fieldAttrEntity);
                        if (stockObj != null) {
                            attrArray.add(stockObj);
                        }
                    } else {
                        // 上面时总库存，这里需要展示分仓库存
                        for (int i = 0; i < warehouseArray.size(); i++) {
                            JSONObject jsonObject = warehouseArray.getJSONObject(i);
                            Long warehouseId = jsonObject.getLong(StringConstant.SAAS_LINK_BUSINESS_ID);
                            if (Objects.equals(warehouseId, productWarehouseId)) {
                                Double num = jsonObject.getDouble(StringConstant.NUM);
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(STOCK, num, fieldAttrEntity));
                                // 防止脏数据多条命中
                                break;
                            }
                        }
                    }
                    break;
                case UNIT:
                    // 单位回显 存的key是0,1,2 回显对应的单位
                    String productUnit = outstockProductExt.getProductUnit();
                    String unitStr = productModel.getProductUnitTextByValue(productUnit, fieldAttrEntity);
                    JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(UNIT, unitStr, fieldAttrEntity));
                    break;
                case BATCH:
                    JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(BATCH, outstockProductExt.getBatch(), fieldAttrEntity));
                    break;
                case GUARANTEE_PERIOD:
                    Double period = outstockProductExt.getGuaranteePeriod() == null ? 0D : outstockProductExt.getGuaranteePeriod() / (double) 86400;
                    JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(GUARANTEE_PERIOD, period, fieldAttrEntity));
                    break;
                case PRODUCE_DATE:
                    Long productDate = outstockProductExt.getProduceDate();
                    String date = productDate == null ? "" : DateTimeUtil.getStringEpochSecond(productDate, DateTimeUtil.SDFDate);
                    JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(PRODUCE_DATE, date, fieldAttrEntity));
                    break;
                case MEMO:
                    JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(MEMO, Objects.toString(outstockProductExt.getMemo(), ""), fieldAttrEntity));
                    break;
                case THUMBNAIL:
                    JSONArray defaultImage = new JSONArray(Collections.singletonList(StringConstant.DEFAULT_IMAGES));
                    JSONArray imageList = outstockProductExt.getImageUrlArray() == null ? defaultImage : outstockProductExt.getImageUrlArray();
                    productObj.put(ProductEnum.THUMBNAIL.getSaasAttr(), imageList);
                    break;
                default:
                    break;
            }

        }
        productObj.put("result", attrArray);
        productObj.put(StringConstant.SAAS_LINK_BUSINESS_ID, productId);
        productObj.put(StringConstant.BUSINESS_PRODUCT_ID, outstockProductExtId);
        productObj.put("parentId", outstockProductExt.getParentId());
        // TODO 库存产品自定义字段的回显
        return productObj;
    }

    @Override
    public void dataConsistencyUpdateWarehouse(String corpid, Long dataId, String name) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery(OutstockEnum.getEsAttr4Keyword(OutstockEnum.WAREHOUSE_ID), dataId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OUTSTOCK, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<OutstockEntityExt> outstockEntityExtList = outstockModel.findEntitys(param);
            if (Objects.nonNull(outstockEntityExtList) && !outstockEntityExtList.isEmpty()) {
                List<OutstockUpdateDTO> outstockUpdateDTOList = new ArrayList<>();
                for (OutstockEntityExt entityExt : outstockEntityExtList) {
                    JSONObject data = new JSONObject();
                    data.put(OutstockEnum.WAREHOUSE_ID_LINKED_TEXT.getAttr(), name);
                    OutstockUpdateDTO outstockUpdateDTO = new OutstockUpdateDTO();
                    outstockUpdateDTO.setId(entityExt.getId());
                    outstockUpdateDTO.setData(data);
                    outstockUpdateDTOList.add(outstockUpdateDTO);
                }

                OutstockUpdateBatchDTO outstockUpdateBatchDTO = new OutstockUpdateBatchDTO();
                outstockUpdateBatchDTO.setCorpid(corpid);
                outstockUpdateBatchDTO.setOutstockList(outstockUpdateDTOList);
                updateBatch(outstockUpdateBatchDTO);
            }

        } catch (Exception e) {
            LOG.error("OutstockServiceImpl.dataConsistencyUpdateWarehouse 出错， corpid=" + corpid + "  warehouseId=" + dataId + "  warehouseName=" + name, e);
        }
    }

    @Override
    public void updateBatchByBusinessRule(OutstockUpdateByBusinessRuleDTO outstockUpdateByBusinessRuleDTO) throws XbbException {
        try {
            String corpid = outstockUpdateByBusinessRuleDTO.getCorpid();
            List<PaasFormDataEntityExt> formDataList = outstockUpdateByBusinessRuleDTO.getFormDataList();
            List<UpdateDataEntity> updateList = ExplainUtil.getUpdateValueByBusinessRule(formDataList, corpid, outstockUpdateByBusinessRuleDTO.getOperations());

            if (!updateList.isEmpty()) {
                outstockModel.updateBatch(updateList, corpid);
                RuleBusinessLogDTO businessLogDTO = new RuleBusinessLogDTO();
                BeanUtil.copyProperties(outstockUpdateByBusinessRuleDTO, businessLogDTO);
                businessLogDTO.setFormDataList(formDataList);
                ruleBusinessLogger.writeLog(businessLogDTO, updateList);
            }
        } catch (Exception e) {
            LOG.error("outstockService.updateFormDataByBusinessRule根据业务规则更新数据出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public ProductSummaryVO summaryProductList(BusinessProductListDTO businessProductListDTO) throws XbbException {
        // 获取参数
        String corpid = businessProductListDTO.getCorpid();
        Long dataId = businessProductListDTO.getDataId();
        PaasFormDataEntityExt paasFormDataEntityExt = proGetHelp.getByKey(dataId, businessProductListDTO.getBusinessType(), businessProductListDTO.getSaasMark(), corpid);
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, corpid);
        modelMap.put("outWarehouseId", dataId);
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put("columns", "product_num,product_id,cost,product_price,price_data,rate");
        List<OutstockProductEntity> outstockProductEntities = outstockProductModel.findEntitys(modelMap);
        ProductSummaryVO businessProductListVO = new ProductSummaryVO();
        Double num = 0D;
        Double rate;
        Set<Long> productIds = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (OutstockProductEntity productEntity : outstockProductEntities) {
            rate = productEntity.getRate() == null ? 1D : productEntity.getRate();
            productIds.add(productEntity.getProductId());
            Double productNum = productEntity.getProductNum() != null ? productEntity.getProductNum() : 0D;
            num = Arith.add(num, Arith.div(productNum,rate));
        }
        Integer productSize = outstockProductEntities.size();
        String summaryInfo = String.format(I18nMessageUtil.getMessage(StringConstant.PRODUCTS_TYPE_NUM), productSize, Arith.doubleToBigDecimal(num));
        businessProductListVO.setSummaryInfo(summaryInfo);
        PaasFormExplainEntity productExplains = paasFormExplainModel.getByBusinessType(XbbRefTypeEnum.PRODUCT.getCode(), corpid);
        PaasFormExplainEntity outstockExplains = paasFormExplainModel.getByBusinessType(businessProductListDTO.getBusinessType(), corpid);
        if (Objects.isNull(productExplains) || Objects.isNull(outstockExplains)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> productExplainMap = ExplainUtil.getExplainMap(productExplains.getExplains(), null);
        Map<String, FieldAttrEntity> outstockExplainMap = ExplainUtil.getExplainMap(outstockExplains.getExplains(), null);
        FieldAttrEntity outstockFieldAttrEntity = outstockExplainMap.getOrDefault(OutstockEnum.PRODUCT.getAttr(), null);
        SubFormPoJo subFormPoJo = outstockFieldAttrEntity.getSubForm();
        List<? extends FieldAttrEntity> subFieldAttrList = subFormPoJo.getItems();
        FieldAttrEntity stockFieldAttrEntity = new FieldAttrEntity();
        // 售价合计可见性跟随售价 售价小计
        FieldAttrEntity sellingPriceFieldAttrEntity = new FieldAttrEntity();
        FieldAttrEntity sellingPriceTotalFieldAttrEntity = new FieldAttrEntity();
        for (FieldAttrEntity fieldAttrEntity : subFieldAttrList) {
            if (Objects.equals(fieldAttrEntity.getAttr(), OutstockProductEnum.NUM.getAttr())) {
                stockFieldAttrEntity = fieldAttrEntity;
            } else if (Objects.equals(fieldAttrEntity.getAttr(), SelectProductEnum.SELLING_PRICE.getAttr())){
                sellingPriceFieldAttrEntity = fieldAttrEntity;
            } else if (Objects.equals(fieldAttrEntity.getAttr(), SelectProductEnum.SUBTOTAL.getAttr())){
                sellingPriceTotalFieldAttrEntity = fieldAttrEntity;
            }
        }
        FieldAttrEntity priceFieldAttrEntity = productExplainMap.getOrDefault(ProductEnum.PRICE.getAttr(), new FieldAttrEntity());
        FieldAttrEntity costFieldAttrEntity = productExplainMap.getOrDefault(ProductEnum.COST.getAttr(), new FieldAttrEntity());
        FieldAttrEntity numFieldAttrEntity = productExplainMap.getOrDefault(ProductEnum.STOCK.getAttr(), new FieldAttrEntity());
        Integer amountPrecision = priceFieldAttrEntity.getAccuracy();
        Integer costPrecision = costFieldAttrEntity.getAccuracy();
        Integer numPrecision = numFieldAttrEntity.getAccuracy();
        Integer showSalePriceFlag = 1;

        // 成本字段是否可见
        boolean hideCost = false;
        boolean hideNum = false;
        // 售价字段是否可见
        boolean hideSellPrice  = false;
        Map<Long, PaasFormDataEntityExt> productMap = productService.getProductMapByIdIn(productIds, corpid, DelEnum.NORMAL);
        for (OutstockProductEntity outstockProduct : outstockProductEntities) {
            Long productId = outstockProduct.getProductId();
            PaasFormDataEntityExt childProduct = productMap.get(productId);
            if (!hideCost) {
                //协同团队
                Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                userTeamService.getUserIdMap(Collections.singletonList(productId), corpid, XbbRefTypeEnum.PRODUCT.getCode(), false, mainUserMap, coUserMap);
                HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
                BeanUtil.copyProperties(businessProductListDTO, handlerExplainDTO);
                if (Objects.nonNull(childProduct) && Objects.nonNull(childProduct.getCreatorId())) {
                    handlerExplainDTO.setCreatorId(childProduct.getCreatorId());
                }
                handlerExplainDTO.setOwnerId(mainUserMap.getOrDefault(productId, new ArrayList<>()));
                handlerExplainDTO.setCoUserId(coUserMap.getOrDefault(productId, new ArrayList<>()));
                hideCost = ExplainUtil.isFieldNeedHide(costFieldAttrEntity, handlerExplainDTO);
                hideNum = ExplainUtil.isFieldNeedHide(stockFieldAttrEntity,handlerExplainDTO);
                // 售价、售价小计有一个隐藏就隐藏掉售价合计
                hideSellPrice = ExplainUtil.isFieldNeedHide(sellingPriceFieldAttrEntity, handlerExplainDTO) || ExplainUtil.isFieldNeedHide(sellingPriceTotalFieldAttrEntity, handlerExplainDTO);
            }
        }
        // 成本字段是否启用
        boolean isCostOpen = false;
        if (costFieldAttrEntity != null && Objects.equals(costFieldAttrEntity.getIsOpen(), 1) && Objects.equals(costFieldAttrEntity.getVisible(), 1)) {
            isCostOpen = true;
        }
        OutstockEntityExt outstockEntityExt = new OutstockEntityExt();
        BeanUtil.copyProperties(paasFormDataEntityExt, outstockEntityExt);
        showSalePriceFlag = hideSellPrice ? 0 : 1;
        JSONObject otherObj = setOutstockTotalAttr(corpid, outstockEntityExt, outstockProductEntities, showSalePriceFlag, hideCost, isCostOpen, amountPrecision, costPrecision, numPrecision);
        // 打印那边需要
        otherObj.put("hidePrice", hideSellPrice);
        if (hideNum) {
            otherObj.put("outNumTotal","*****");
        }
        businessProductListVO.setOthers(otherObj);
        businessProductListVO.setBusinessType(businessProductListDTO.getBusinessType());
        return businessProductListVO;
    }


    @Override
    public void dataConsistemcyUpdateCustomerName(String corpid, Long customerId, String customerName) {
        try{
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()))
                    .filter(termQuery(ContractOutstockEnum.getEsAttr4Keyword(ContractOutstockEnum.LINK_CUSTOMER),customerId))
                    .filter(termsQuery(ContractOutstockEnum.getEsAttr4Keyword(ContractOutstockEnum.TYPE), Arrays.asList(OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode(), OutstockTypeEnum.WORK_ORDER_OUTSTOCK.getCode())));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_CONTRACT_OUTSTOCK, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<OutstockEntityExt> outstockEntityExtList = outstockModel.findEntitys(param);

            if (Objects.nonNull(outstockEntityExtList) && !outstockEntityExtList.isEmpty()){
                List<OutstockUpdateDTO> outStockUpdateDTOList = new ArrayList<>();
                for (OutstockEntityExt entityExt : outstockEntityExtList) {
                    OutstockUpdateDTO outstockUpdateDTO = new OutstockUpdateDTO();
                    outstockUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(ContractOutstockEnum.LINK_CUSTOMER_HIDE.getAttr(), customerName);
                    outstockUpdateDTO.setData(data);
                    outStockUpdateDTOList.add(outstockUpdateDTO);
                }
                OutstockUpdateBatchDTO outstockUpdateBatchDTO = new OutstockUpdateBatchDTO();
                outstockUpdateBatchDTO.setCorpid(corpid);
                outstockUpdateBatchDTO.setOutstockList(outStockUpdateDTOList);
                updateBatch(outstockUpdateBatchDTO);
            }
        }catch (Exception e){
            LOG.error("OutstockServiceImpl.dataConsistencyUpdateCustomer 出错，corpid=" + corpid + "  customerId=" + customerId + " customerName=" + customerName, e);
        }
    }

    @Override
    public List<Long> hasDownstreamList(String corpid, List<Long> idIn, int type) throws XbbException {
        return outstockModel.hasDownstreamList(corpid, idIn, type);
    }

    @Override
    public void formatBatchExplain(List<FieldAttrEntity> fieldAttrEntityList, String enable) {
        String productAttr = OutstockEnum.PRODUCT.getAttr();
        BatchSeqExplainHelp.getInstance().formatExplain4BatchAffectProductAttr(fieldAttrEntityList, enable, productAttr);
    }

    @Override
    public void formatBatchOrSeqExplain(List<FieldAttrEntity> fieldAttrEntityList, String enable, String alias) {
        if (CompanyConfigEnum.ENABLE_BATCH_SHELF_MANAGEMENT.getAlias().equals(alias)) {
            formatBatchExplain(fieldAttrEntityList, enable);
        }
    }

    /**
     * 供应商名称一致性同步
     * @param corpid 公司ID
     * @param supplierId 供应商id
     * @param supplierName 供应商名称
     * @throws XbbException
     * @since v1.0
     * @version v1.0
     */
    @Override
    public void dataConsistencyUpdateSupplier(String corpid, Long supplierId, String supplierName) throws XbbException {
        try {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(ParameterConstant.CORPID, corpid);
            param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
            param.put("type", OutstockTypeEnum.RETURNED_PURCHASE_OUTSTOCK.getCode());
            param.put("supplierid", supplierId);
            List<OutstockEntityExt> entityExts = outstockModel.getBySupplierId(param);
            //更新数据库的中的data的text_67供应商名称
            List<UpdateDataEntity> updateDataEntityList = new ArrayList<>();
            if(Objects.nonNull(entityExts)){
                for (OutstockEntityExt entityExt : entityExts) {
                    JSONObject data1 = entityExt.getData();
                    data1.put(ReturnedPurchaseEnum.LINK_SUPPLIER_HIDE.getAttr(),supplierName);
                    updateDataEntityList.add(ExplainUtil.getUpdateData(entityExt.getDataId(),data1, corpid));
                }
                outstockModel.updateBatch(updateDataEntityList, corpid);
            }
        }catch (Exception e){
            LOG.error("OutstockServiceImpl.dataConsistencyUpdateSupplier 出错，corpid=" + corpid + "  supplierId=" + supplierId + " supplierName=" + supplierName, e);

        }
    }

    @Override
    public void updateBatchLabelAttr(AddLabelDTO addLabelDTO, List<PaasFormDataEntityExt> addBatchList, Boolean addOrDelete) throws XbbException {
        OutstockUpdateBatchDTO outstockUpdateBatchDTO = new OutstockUpdateBatchDTO();
        BeanUtil.copyProperties(addLabelDTO, outstockUpdateBatchDTO);
        List<OutstockUpdateDTO> outstockList = new ArrayList<>();
        addBatchList.forEach(item->{
            OutstockUpdateDTO updateDTO= new OutstockUpdateDTO();
            updateDTO.setData(item.getData());
            updateDTO.setId(item.getId());
            outstockList.add(updateDTO);
        });
        outstockUpdateBatchDTO.setOutstockList(outstockList);
        // 出库单编辑保存
        updateBatch(outstockUpdateBatchDTO);

    }

    @Override
    public void afterSaveForWorkflow(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        JSONObject data = saasFormSaveDTO.getNewData();
        Integer type = data.getInteger(OutstockEnum.TYPE.getAttr());
        String corpid = saasFormSaveDTO.getCorpid();
        Long refId = Objects.isNull(data.getLong(OutstockEnum.REF_ID.getAttr())) ? 0L : data.getLong(OutstockEnum.REF_ID.getAttr());
        // 改为新建时进行以下逻辑：产品保存、库存更新、上游单据更新
        // 获取对应数据
        PaasFormDataEntity newEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        JSONObject dataList = newEntity.getData();
        // 获取关联产品的数据
        JSONArray productJsonArray = dataList.getJSONArray(OutstockEnum.PRODUCT.getAttr());
        String productStr = JSON.toJSONString(productJsonArray);
        // 更新出库产品库存
        Long outstockId = newEntity.getId();
        //上游单据id
        Long formId = saasFormSaveDTO.getNewPaasFormDataEntity().getFormId();
        saveProduct(productJsonArray, corpid, outstockId, type, refId, formId, true);
    }

    @Override
    public void afterSaveForUpdateWorkflow(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        String corpid = saasFormSaveDTO.getCorpid();
        Integer taskType = saasFormSaveDTO.getTaskType();
        boolean isCommitAgain = Objects.equals(TaskTypeEnum.AGAIN_COMMIT.getType(),taskType);
        List<OutstockProductEntity> outstockProductEntityList = outstockProductModel.getProductsByOutstockIdIn( saasFormSaveDTO.getCorpid(), saasFormSaveDTO.getNewPaasFormDataEntity().getDataId(), Arrays.asList( DelEnum.NORMAL.getDel(), DelEnum.APPROVE_FAILED.getDel()));
        Set<Long> outStockProductIdList = new HashSet<>();
        // 每个产品变化前的销售出库数量
        Map<Long,Double> beforeSmartProductNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 每个合同产品变化前的销售出库数量
        Map<String,Double> beforeBalamceNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,OutstockProductEntity> delMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> contractProductIdList = new ArrayList<>();
        Set<Long> contractIdSet = new HashSet<>();
        outstockProductEntityList.forEach(item->{
            outStockProductIdList.add(item.getId());
            delMap.put(item.getId(),item);
            if (beforeSmartProductNumMap.containsKey(item.getProductId())){
                beforeSmartProductNumMap.put(item.getProductId(),Arith.add(beforeSmartProductNumMap.get(item.getProductId()),item.getProductNum()));
            }else {
                beforeSmartProductNumMap.put(item.getProductId(),item.getProductNum());
            }
            Long refProductId = item.getRefProductId();
            Long productId = item.getProductId();
            Long contractId = item.getRefId();
            if (Objects.nonNull(refProductId)){
                contractProductIdList.add(refProductId);
                contractIdSet.add(contractId);
                String onlyKey = refProductId + "_" + productId;
                if (beforeBalamceNumMap.containsKey(onlyKey)){
                    beforeBalamceNumMap.put(onlyKey,Arith.add(beforeBalamceNumMap.get(onlyKey),item.getProductNum()));
                }else {
                    beforeBalamceNumMap.put(onlyKey,item.getProductNum());
                }
            }
        });
        JSONArray updateOutstockProductList = new JSONArray();
        JSONArray insertOutstockProductList = new JSONArray();
        JSONObject data = saasFormSaveDTO.getNewData();
        List<Long> updateInstockProductIds = new ArrayList<>();
        JSONArray productJsonArray = data.getJSONArray(InstockEnum.PRODUCT.getAttr());
        String productStr = JSON.toJSONString(productJsonArray);
        for (int i = 0; i < productJsonArray.size(); i++) {
            JSONObject instockProduct = productJsonArray.getJSONObject(i);
            Long instockProductId = instockProduct.getLong(BusinessConstant.PRODUCT_SUB_ID);
            if (instockProductId != null) {
                updateInstockProductIds.add(instockProductId);
                updateOutstockProductList.add(instockProduct);
            } else {
                insertOutstockProductList.add(instockProduct);
            }
        }
        PaasFormDataEntity newEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        Long instockId = newEntity.getId();
        Integer type = data.getInteger(OutstockEnum.TYPE.getAttr());
        Long refId = Objects.isNull(data.getLong(OutstockEnum.REF_ID.getAttr())) ? 0L : data.getLong(OutstockEnum.REF_ID.getAttr());
        Long formId = saasFormSaveDTO.getNewPaasFormDataEntity().getFormId();
        if (!insertOutstockProductList.isEmpty()) {
            saveProduct(insertOutstockProductList, corpid, instockId,type,refId,formId, true);
        }
        updateOutsotckProduct(updateOutstockProductList, corpid, instockId, type, refId, formId);
        outStockProductIdList.removeAll(updateInstockProductIds);
        if (CollectionsUtil.isNotEmpty(outStockProductIdList)) {
            outstockProductModel.deleteBatchById(outStockProductIdList, corpid, DelEnum.DELETE.getDel());
        }

        // 销售出库单时更新采购结存及智能补货数据
        if (CollectionUtils.isNotEmpty(updateOutstockProductList) && Objects.equals(data.getInteger(OutstockEnum.TYPE.getAttr()),OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())){
            // 新建销售出库单采购结存表更新数据 计算建议采购量用
            List<String> onlyKeyList = new ArrayList<>();
            // 新建销售出库更新智能补货表中未出库数量
            List<Long> productIdList = new ArrayList<>();
            Map<Long,Double> afterSmartMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String,Double> afterBalanceMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (int i = 0; i < updateOutstockProductList.size(); i++) {
                JSONObject jsonObject = updateOutstockProductList.getJSONObject(i);
                Long productId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
                Double productNum = jsonObject.getDouble(OutstockProductEnum.NUM.getAttr());
                Long contractProductId = jsonObject.getLong("refProductId");
                productIdList.add(productId);
                if (afterSmartMap.containsKey(productId)){
                    afterSmartMap.put(productId,Arith.add(afterSmartMap.get(productId),productNum));
                }else {
                    afterSmartMap.put(productId,productNum);
                }
                if (Objects.nonNull(contractProductId)){
                    String onlyKey = contractProductId + "_" + productId;
                    onlyKeyList.add(onlyKey);
                    if (afterBalanceMap.containsKey(onlyKey)){
                        afterBalanceMap.put(onlyKey,Arith.add(afterBalanceMap.get(onlyKey),productNum));
                    }else {
                        afterBalanceMap.put(onlyKey,productNum);
                    }
                }
            }
            if (CollectionUtils.isNotEmpty(onlyKeyList)){
                Map<String,Double> balanceChangeNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (String onlyKey : onlyKeyList) {
                    // 重新提交的话 全部重新计算 不是重新提交的话需要计算差值
                    Double beforeNum = 0D;
                    if (!isCommitAgain){
                         beforeNum = beforeBalamceNumMap.getOrDefault(onlyKey, 0D);
                    }
                    Double afterNum = afterBalanceMap.getOrDefault(onlyKey, 0D);balanceChangeNumMap.put(onlyKey,Arith.sub(afterNum,beforeNum));
                    balanceChangeNumMap.put(onlyKey,Arith.sub(afterNum,beforeNum));
                }
                List<PurchaseBalanceEntity> purchaseBalanceEntityList = purchaseBalanceModel.findByOnlyKeys(corpid, onlyKeyList);
                if (CollectionUtils.isNotEmpty(purchaseBalanceEntityList)){
                    for (PurchaseBalanceEntity purchaseBalanceEntity : purchaseBalanceEntityList) {
                        String onlyKey = purchaseBalanceEntity.getOnlyKey();
                        Double balanceNum = purchaseBalanceEntity.getBalanceNum();
                        Double exceedStockNum = purchaseBalanceEntity.getExceedStockNum();
                        Double changeNum = balanceChangeNumMap.getOrDefault(onlyKey, 0D);
                        // 变更数量大于0 说明销售出库数量从小变大了
                        if (changeNum >= 0){
                            purchaseBalanceEntity.setBalanceNum(balanceNum >= Math.abs(changeNum) ? Arith.sub(balanceNum,Math.abs(changeNum)) : 0);
                            purchaseBalanceEntity.setExceedStockNum(balanceNum >= Math.abs(changeNum) ? exceedStockNum:Arith.add(exceedStockNum,Arith.sub(Math.abs(changeNum),balanceNum)));
                        }else {
                            // 编辑数量变小则先填补超发 全部填补完后剩余的填补结存
                            purchaseBalanceEntity.setExceedStockNum(exceedStockNum >= Math.abs(changeNum) ? Arith.sub(exceedStockNum,Math.abs(changeNum)):0D);
                            purchaseBalanceEntity.setBalanceNum(exceedStockNum >= Math.abs(changeNum) ? balanceNum:Arith.add(balanceNum,Arith.sub(Math.abs(changeNum),exceedStockNum)));
                        }
                    }
                    try {
                        purchaseBalanceModel.updateBatch(purchaseBalanceEntityList,corpid);
                    }catch (Exception e){
                        LOG.error("OutstockServiceImpl.afterSaveForUpdateWorkflow() 更新采购结存表数据时出错", e);
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                    }
                }
            }
            if (CollectionUtils.isNotEmpty(productIdList)){
                Map<Long,Double> changeSmartNum = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (Long productId : productIdList) {
                    Double beforeNum = 0D;
                    if (!isCommitAgain){
                        beforeNum = beforeSmartProductNumMap.getOrDefault(productId, 0D);
                    }
                    Double afterNum = afterSmartMap.getOrDefault(productId, 0D);
                    changeSmartNum.put(productId,Arith.sub(afterNum,beforeNum));
                }
                List<SmartReplenishmentEntity> smartReplenishmentEntityList = smartReplenishmentModel.getByProductList(corpid, productIdList);
                if (CollectionUtils.isNotEmpty(smartReplenishmentEntityList)){
                    for (SmartReplenishmentEntity smartReplenishmentEntity : smartReplenishmentEntityList) {
                        Long productId = smartReplenishmentEntity.getProductId();
                        Double waitOutstockNum = smartReplenishmentEntity.getWaitOutstockNum();
                        Double changeNum = changeSmartNum.getOrDefault(productId, 0D);
                        smartReplenishmentEntity.setWaitOutstockNum(Arith.sub(waitOutstockNum,changeNum));
                    }
                    try {
                        smartReplenishmentModel.updateBatch(smartReplenishmentEntityList,corpid);
                    }catch (Exception e){
                        LOG.error("OutstockServiceImpl.afterSaveForUpdateWorkflow() 插入智能补货数据时出错", e);
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                    }
                }
            }
        }

        // 重新提交时不用计算删除掉的数据 因为拒绝时删除掉的已经删除了 重新提交就不用管删除掉的产品了 只处理新增和编辑的产品就行
        if (CollectionUtils.isNotEmpty(outStockProductIdList) && !isCommitAgain){
            List<OutstockProductEntity> delList = new ArrayList<>();
            outStockProductIdList.forEach(item -> {
                delList.add(delMap.get(item));
            });
            if (CollectionUtils.isNotEmpty(delList)){
                List<String> onlyKyeList = new ArrayList<>();
                List<Long> productIdList = new ArrayList<>();
                Map<Long,Double> delSmartNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String,Double> delBalanceNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (OutstockProductEntity outstockProductEntity : delList) {
                    Long productId = outstockProductEntity.getProductId();
                    productIdList.add(productId);
                    Long refProductId = outstockProductEntity.getRefProductId();
                    Double productNum = outstockProductEntity.getProductNum();
                    if (delSmartNumMap.containsKey(productId)){
                        delSmartNumMap.put(productId,Arith.add(delSmartNumMap.get(productId),productNum));
                    }else {
                        delSmartNumMap.put(productId,productNum);
                    }
                    if (Objects.nonNull(refProductId)){
                        String onlyKey = refProductId + "_" + productId;
                        onlyKyeList.add(onlyKey);
                        if (delBalanceNumMap.containsKey(onlyKey)){
                            delBalanceNumMap.put(onlyKey,Arith.add(delBalanceNumMap.get(onlyKey),productNum));
                        }else {
                            delBalanceNumMap.put(onlyKey,productNum);
                        }
                    }
                }
                if (CollectionUtils.isNotEmpty(productIdList)){
                    List<SmartReplenishmentEntity> smartReplenishmentEntityList = smartReplenishmentModel.getByProductList(corpid, productIdList);
                    if (CollectionUtils.isNotEmpty(smartReplenishmentEntityList)){
                        for (SmartReplenishmentEntity smartReplenishmentEntity : smartReplenishmentEntityList) {
                            Long productId = smartReplenishmentEntity.getProductId();
                            Double waitOutstockNum = smartReplenishmentEntity.getWaitOutstockNum();
                            Double changeNum = delSmartNumMap.getOrDefault(productId, 0D);
                            smartReplenishmentEntity.setWaitOutstockNum(Arith.sub(waitOutstockNum,changeNum));
                        }
                        try {
                            smartReplenishmentModel.updateBatch(smartReplenishmentEntityList,corpid);
                        }catch (Exception e){
                            LOG.error("OutstockServiceImpl.afterSaveForUpdateWorkflow() 插入智能补货数据时出错", e);
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                        }
                    }
                }
                if (CollectionUtils.isNotEmpty(onlyKyeList)){
                    List<PurchaseBalanceEntity> purchaseBalanceEntityList = purchaseBalanceModel.findByOnlyKeys(corpid, onlyKyeList);
                    if (CollectionUtils.isNotEmpty(purchaseBalanceEntityList)){
                        for (PurchaseBalanceEntity purchaseBalanceEntity : purchaseBalanceEntityList) {
                            String onlyKey = purchaseBalanceEntity.getOnlyKey();
                            Double balanceNum = purchaseBalanceEntity.getBalanceNum();
                            Double delProductNum = delBalanceNumMap.getOrDefault(onlyKey, 0D);
                            Double exceedStockNum = purchaseBalanceEntity.getExceedStockNum();
                            // 删除数量 如果大于超发的 则超发库存全部回退 多余的回到结存 小于的话全部回退到超发库存
                            purchaseBalanceEntity.setExceedStockNum(delProductNum >= exceedStockNum ? 0D : Arith.sub(exceedStockNum,delProductNum));
                            // 删除的数量如果大于超发 则结存数量为之前的加上删除的大于超发的那部分  如果小于超发 则全部回退到超发 结存不变
                            purchaseBalanceEntity.setBalanceNum(delProductNum >= exceedStockNum ? Arith.add(balanceNum,Arith.sub(delProductNum,exceedStockNum)): balanceNum);
                        }
                        try {
                            purchaseBalanceModel.updateBatch(purchaseBalanceEntityList,corpid);
                        }catch (Exception e){
                            LOG.error("OutstockServiceImpl.afterSaveForUpdateWorkflow() 更新采购结存表数据时出错", e);
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
                        }
                    }
                }
            }
        }
        // 处理合同产品表中缺货数量字段
        if(CollectionsUtil.isNotEmpty(contractProductIdList)){
            List<ContractProductEntity> contractProductEntityList = contractProductModel.getById(contractProductIdList, corpid);
            if (CollectionsUtil.isNotEmpty(contractProductEntityList)) {
                contractHelp.handleWaitPurchaseNum(corpid, contractProductEntityList, contractIdSet);
                try {
                    contractProductModel.updateBatch(contractProductEntityList, corpid);
                } catch (Exception e) {
                    LOG.error("OutstockServiceImpl.afterSaveForUpdateWorkflow() 更新合同产品表中缺货数量时出错", e);
                }
            }
        }
    }

    /**
     * 更新出库单的出库产品，给工作流审批使用
     * @param productArray
     * @param corpid
     * @param outstockId
     * @param type
     * @param refId
     * @param formId
     * @return
     * @throws XbbException
     */
    public List<OutstockProductEntity> updateOutsotckProduct(JSONArray productArray, String corpid, Long outstockId, Integer type, Long refId, Long formId) throws XbbException {
        if (productArray == null || productArray.isEmpty()) {
            return new ArrayList<>();
        }
        // 更新
        List<OutstockProductEntity> addOutstockProductEntityList = new ArrayList<>();
        Map<Long, PaasFormDataEntityExt> productMap = formDataValidateProductHelp.product2saveMap(corpid,productArray);
        long now = DateTimeUtil.getInt();
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject jsonObject = productArray.getJSONObject(i);
            // 移除序列号相关数据，不存入关联产品数据中
            jsonObject.remove(ProductConstant.SEQ);
            jsonObject.remove(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr());
            jsonObject.remove(ProductEnum.ENABLE_BATCH_SHELF_LIFE.getSaasAttr());

            Long pageProductId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            JSONObject productData = productMap.get(pageProductId).getData();
            OutstockProductEntity entity = new OutstockProductEntity();
            entity.setId(jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID));
            entity.setCorpid(corpid);
            entity.setProductId(pageProductId);
            entity.setParentId(productData.getLong(ProductEnum.PARENT_ID.getAttr()));
            jsonObject.put(ProductEnum.PARENT_ID.getSaasAttr(), productData.getLong(ProductEnum.PARENT_ID.getAttr()));
            entity.setProductNo(productData.getString(ProductEnum.PRODUCT_NO.getAttr()));
            entity.setProductNum(jsonObject.getDouble(OutstockProductEnum.NUM.getAttr()));
            entity.setOutWarehouseId(outstockId);
            entity.setInstockNum(0D);
            entity.setType(type);
            entity.setRefId(refId);
            entity.setFormId(formId);
            if (Objects.nonNull(jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID))) {
                entity.setRefProductId(jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID));
            }
            saasSaveHelp.formatLinkBusiness4Save(jsonObject,OutstockProductEnum.WAREHOUSE.getAttr(), "warehouseName", FieldTypeEnum.LINK_BUSINESS_SINGLE.getType());
            entity.setWarehouseId(jsonObject.getLong(OutstockProductEnum.WAREHOUSE.getAttr()));
            entity.setWarehouseName(jsonObject.getString("warehouseName"));
            entity.setProductName(productData.getString(ProductEnum.NAME.getAttr()));
            entity.setProductSpecification(productData.getString(ProductEnum.SPECIFICATION_LINK_TEXT.getAttr()));
            entity.setMemo(jsonObject.getString(OutstockProductEnum.MEMO.getAttr()));
            entity.setBatch(Objects.isNull(jsonObject.getString(OutstockProductEnum.BATCH.getAttr())) ? "" : jsonObject.getString(OutstockProductEnum.BATCH.getAttr()));
            Long guaranteePeriod = Objects.isNull(jsonObject.getLong(OutstockProductEnum.GUARANTEE_PERIOD.getAttr())) ? 0L : jsonObject.getLong(OutstockProductEnum.GUARANTEE_PERIOD.getAttr()) * TimeConstant.SECONDS_PER_DAY;
            entity.setGuaranteePeriod(guaranteePeriod);
            Long produceDate = Objects.isNull(jsonObject.getLong(OutstockProductEnum.PRODUCE_DATE.getAttr())) ? 0L : jsonObject.getLong(OutstockProductEnum.PRODUCE_DATE.getAttr());
            entity.setProduceDate(produceDate);
            entity.setCost(Objects.isNull(jsonObject.getDouble(ProductEnum.COST.getAttr())) ? 0D : jsonObject.getDouble(ProductEnum.COST.getAttr()));
            if (Objects.equals(type,OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode())){
                entity.setDiscount(jsonObject.getDouble(ContractOutstockProductEnum.DISCOUNT.getAttr()));
                entity.setProductPrice(jsonObject.getDouble(ContractOutstockProductEnum.SELLING_PRICE.getAttr()));
            }
            jsonObject.put(OutstockProductEnum.TOTAL_COST.getAttr(), Arith.mul(entity.getCost(), entity.getProductNum()));
            entity.setData(jsonObject);
            Integer enableMultiUnit = productData.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr());
            if (Objects.equals(enableMultiUnit, 1)) {
                formDataValidateProductHelp.setBusinessUnit(jsonObject, entity);
                entity.setProductUnit(jsonObject.getString(SelectProductEnum.UNIT.getAttr()));
            } else {
                entity.setProductUnit(productData.getString(ProductEnum.UNIT.getAttr()));
            }
            entity.setUpdateTime(now);
            entity.setDel(0);
            addOutstockProductEntityList.add(entity);

        }
        outstockProductModel.updateMulti(addOutstockProductEntityList, corpid);
        return addOutstockProductEntityList;
    }

    @Override
    public void dataConsistencyUpdateContract(String corpid, Long contractId, String serialNo) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery(ContractOutstockEnum.getEsAttr4Keyword(ContractOutstockEnum.TYPE), OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode()))
                    .filter(termQuery(ContractOutstockEnum.getEsAttr4Keyword(ContractOutstockEnum.REF_ID), contractId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OUTSTOCK, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<OutstockEntityExt> outstockEntityExtList = outstockModel.findEntitys(param);
            if (Objects.nonNull(outstockEntityExtList) && !outstockEntityExtList.isEmpty()) {
                List<OutstockUpdateDTO> outstockUpdateDTOList = new ArrayList<>();
                for (OutstockEntityExt entityExt : outstockEntityExtList) {
                    JSONObject oldData = entityExt.getData();
                    if (oldData == null) {
                        continue;
                    }
                    OutstockUpdateDTO outstockUpdateDTO = new OutstockUpdateDTO();
                    outstockUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(ContractOutstockEnum.REF_ID_LINKED_TEXT.getAttr(), serialNo);
                    outstockUpdateDTO.setData(data);
                    outstockUpdateDTOList.add(outstockUpdateDTO);
                }
                OutstockUpdateBatchDTO outstockUpdateBatchDTO = new OutstockUpdateBatchDTO();
                outstockUpdateBatchDTO.setCorpid(corpid);
                outstockUpdateBatchDTO.setOutstockList(outstockUpdateDTOList);
                updateBatch(outstockUpdateBatchDTO);
            }
        } catch (Exception e) {
            LOG.error("OutstockServiceImpl.dataConsistencyUpdateContract fail， corpid=" + corpid + " contractId=" + contractId + "  contractNo=" + serialNo, e);
        }
    }

    @Override
    public double getContractOutstockTotalMoney(JSONObject data, Long dataId, PaasFormDataEsListVO contractOutstockListVO) throws XbbException {
        return OutstockUtil.getContractOutstockTotalMoney(data, dataId, contractOutstockListVO);
    }
}
